/*
 * Copyright 2007 Massachusetts Institute of Technology
 */


// info flow log rollup

#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <zlib.h>
#include "info_flow.h"
#include "osdep.h"

#define FALSE 0
#define TRUE 1

//#include "cpu-all.h"
//#include "vslht.h"


// provides [u]int[8,16,32,64]_t
#include "stdint.h" 


// ptr to first byte of info flow log
char *if_log_base = NULL;      

// ptr to next byte to be written in info flow log
char *if_log_ptr = NULL;      

// size of log
uint32_t if_log_len = 0;   

// turns info-flow rollup off
trl_boolean if_log_only = FALSE;
trl_boolean if_save_log = FALSE;
trl_boolean if_on = FALSE;

trl_boolean info_flow_inner_prof = FALSE;

uint32_t if_log_rollup_count = 0;  

// used to control long we spit out verbose info after
// something interesting happens, like keyboard input. 
uint32_t if_debug_high_counter = 0;

uint32_t if_debug = 0;

// a global -- the current if_op.  for debugging. 
if_op_t if_current_op = UNINITIALIZED;
// more globals
char *if_p_orig;
uint32_t if_current_op_ind = 0;

uint32_t if_key_num = 0;

// used to keep track of counts of info-flow ops.
uint32_t if_op_hist[256];
trl_boolean if_count_ops = FALSE;


uint32_t label_taint_count = 0;
uint32_t delete_taint_count = 0;
uint32_t copy_taint_count = 0;
uint32_t compute_taint_count = 0;

//trl_boolean loglog = TRUE;
trl_boolean loglog = FALSE;
FILE *loglog_fp;

trl_boolean foo=FALSE;
trl_boolean foo2=FALSE;

//vslht *tmh = NULL;

//declare ifregaddr
unsigned long long ifregaddr[16];

// array of flags to indicate if any part of a register is tainted
trl_boolean if_reg_taint[16] = {
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE,
  FALSE
};


char* info_flow_reg_str[16] = {
  "EAX",
  "ECX",
  "EDX",
  "EBX",
  "ESP",
  "EBP",
  "ESI",
  "EDI",
  "T0",
  "T1",
  "A0",
  "Q0",
  "Q1",
  "Q2",
  "Q3",
  "Q4"
};



void *my_malloc (size_t n) {
  void *p;

  p = malloc(n);
  assert (p!=NULL);
  return (p);
}

void *my_calloc(size_t nmember, size_t sze) {
  void *p;

  p = my_malloc(nmember * sze);
  memset(p, 0, nmember * sze);
  return (p);
}

void *my_realloc (void *p, size_t n) {
  void *p2;

  p2 = realloc(p,n);
  assert (p2 != NULL);
  return (p2);
}

void my_free (void *p) {
  free(p);
}


void search_buf_for_pattern(char* buf, int l){
	char* pattern = "ZaP";
	int i,j;

	printf("buf contains: ");
	for(i=0;i<l;i++){
		printf("%c",*(buf+i));
	}

	printf("\r\n");

	for(i=0;i<(l-(strlen(pattern)-1));i++){
		for(j=0;j<strlen(pattern);j++){
			if(*(buf+i+j)!=*(pattern+j))
				break;
		}
		if(j==strlen(pattern)){
 			printf("YAY, we found the pattern going into the hard drive");
			break;
		}
	}	
	
}


struct timeval last_time;


char **if_key_label = NULL;
int if_num_key_labels = 0;
int if_key_label_ind = 0;
char *if_keyboard_label=NULL;
trl_boolean if_keyboard_label_changed = FALSE;

void push_key_label(char *l) {
  // init key label array
  if (if_key_label == NULL) {
    if_num_key_labels = 10;
    if_key_label_ind = 0;
    if_key_label = (char**) my_malloc (sizeof(char *) * if_num_key_labels);
  }
  // grow array
  if (if_key_label_ind == if_num_key_labels) {
    if_num_key_labels *= 2;
    if_key_label = (char **) my_realloc(if_key_label, sizeof(char *) * if_num_key_labels);
  }
  // populate with this label
  if_key_label[if_key_label_ind] = strdup(l);
  if_key_label_ind ++;
}

char* if_network_label=NULL;
trl_boolean if_network_label_changed = FALSE;


char *if_memsuffix_str(if_memsuffixnum_t msn) {
  char *ms = NULL;

  switch (msn) {
  case 0:
    ms = "raw";
    break;
  case 1:
    ms = "kernel";
    break;
  case 2:
    ms = "user";
    break;
  default:
    ms ="WTF_MATE";
  }
  return ms;
}    


// if flag has been set, write new network label in the log
void new_network_label_check(){
  if (if_network_label_changed) { 
    unsigned int i,l; 
    if_network_label_changed = FALSE; 
    printf ("info_flow_new_network_label [%s]\r\n", if_network_label); 
    IFLW_WRAPPER(
		 IFLW_PUT_OP(INFO_FLOW_OP_NEW_NETWORK_LABEL); 
		 l = strlen(if_network_label); 
		 if (l>=IF_MAX_NETWORK_LABEL_LEN) 
		   l = IF_MAX_NETWORK_LABEL_LEN-1; 
		 IFLW_PUT_WORD(l); 
		 for (i=0; i<l; i++) { 
		   IFLW_PUT_BYTE(if_network_label[i]); 
		 } 
		 );
 }
}

// NB: Don't edit this!  
// It gets autogenerated by the script target-i386/create_if_ops.pl




char *if_op_str(if_op_t if_op) {
  char *ifs = NULL;

  switch (if_op) {
  case INFO_FLOW_OP_AAA:
    ifs = "aaa";
    break;
  case INFO_FLOW_OP_AAD:
    ifs = "aad";
    break;
  case INFO_FLOW_OP_AAM:
    ifs = "aam";
    break;
  case INFO_FLOW_OP_AAS:
    ifs = "aas";
    break;
  case INFO_FLOW_OP_ADDL_A0_AL:
    ifs = "addl_a0_al";
    break;
  case INFO_FLOW_OP_ADDL_A0_IM:
    ifs = "addl_a0_im";
    break;
  case INFO_FLOW_OP_ADDL_A0_SS:
    ifs = "addl_a0_ss";
    break;
  case INFO_FLOW_OP_ADDL_EDI_T0:
    ifs = "addl_edi_t0";
    break;
  case INFO_FLOW_OP_ADDL_ESI_T0:
    ifs = "addl_esi_t0";
    break;
  case INFO_FLOW_OP_ADDL_ESP_2:
    ifs = "addl_esp_2";
    break;
  case INFO_FLOW_OP_ADDL_ESP_4:
    ifs = "addl_esp_4";
    break;
  case INFO_FLOW_OP_ADDL_ESP_IM:
    ifs = "addl_esp_im";
    break;
  case INFO_FLOW_OP_ADDL_T0_IM:
    ifs = "addl_t0_im";
    break;
  case INFO_FLOW_OP_ADDL_T0_T1:
    ifs = "addl_t0_t1";
    break;
  case INFO_FLOW_OP_ADDL_T1_IM:
    ifs = "addl_t1_im";
    break;
  case INFO_FLOW_OP_ADDR_ADDL_A0_SEG:
    ifs = "addr_addl_a0_seg";
    break;
  case INFO_FLOW_OP_ADDR_MOVL_A0_SEG:
    ifs = "addr_movl_a0_seg";
    break;
  case INFO_FLOW_OP_ADDR_MOVL_ENV_T0:
    ifs = "addr_movl_env_t0";
    break;
  case INFO_FLOW_OP_ADDR_MOVL_ENV_T1:
    ifs = "addr_movl_env_t1";
    break;
  case INFO_FLOW_OP_ADDR_MOVL_T0_ENV:
    ifs = "addr_movl_t0_env";
    break;
  case INFO_FLOW_OP_ADDR_MOVTL_ENV_T0:
    ifs = "addr_movtl_env_t0";
    break;
  case INFO_FLOW_OP_ADDR_MOVTL_ENV_T1:
    ifs = "addr_movtl_env_t1";
    break;
  case INFO_FLOW_OP_ADDR_MOVTL_T0_ENV:
    ifs = "addr_movtl_t0_env";
    break;
  case INFO_FLOW_OP_ADDR_MOVTL_T1_ENV:
    ifs = "addr_movtl_t1_env";
    break;
  case INFO_FLOW_OP_ADDW_EDI_T0:
    ifs = "addw_edi_t0";
    break;
  case INFO_FLOW_OP_ADDW_ESI_T0:
    ifs = "addw_esi_t0";
    break;
  case INFO_FLOW_OP_ADDW_ESP_2:
    ifs = "addw_esp_2";
    break;
  case INFO_FLOW_OP_ADDW_ESP_4:
    ifs = "addw_esp_4";
    break;
  case INFO_FLOW_OP_ADDW_ESP_IM:
    ifs = "addw_esp_im";
    break;
  case INFO_FLOW_OP_ANDL_A0_FFFF:
    ifs = "andl_a0_ffff";
    break;
  case INFO_FLOW_OP_ANDL_T0_FFFF:
    ifs = "andl_t0_ffff";
    break;
  case INFO_FLOW_OP_ANDL_T0_IM:
    ifs = "andl_t0_im";
    break;
  case INFO_FLOW_OP_ANDL_T0_T1:
    ifs = "andl_t0_t1";
    break;
  case INFO_FLOW_OP_ARPL:
    ifs = "arpl";
    break;
  case INFO_FLOW_OP_BSWAPL_T0:
    ifs = "bswapl_t0";
    break;
  case INFO_FLOW_OP_CLTS:
    ifs = "clts";
    break;
  case INFO_FLOW_OP_CMPXCHG8B_PART1:
    ifs = "cmpxchg8b_part1";
    break;
  case INFO_FLOW_OP_CMPXCHG8B_PART2:
    ifs = "cmpxchg8b_part2";
    break;
  case INFO_FLOW_OP_CPUID:
    ifs = "cpuid";
    break;
  case INFO_FLOW_OP_DAA:
    ifs = "daa";
    break;
  case INFO_FLOW_OP_DAS:
    ifs = "das";
    break;
  case INFO_FLOW_OP_DECL_ECX:
    ifs = "decl_ecx";
    break;
  case INFO_FLOW_OP_DECL_T0:
    ifs = "decl_t0";
    break;
  case INFO_FLOW_OP_DECW_ECX:
    ifs = "decw_ecx";
    break;
  case INFO_FLOW_OP_DIVB_AL_T0:
    ifs = "divb_al_t0";
    break;
  case INFO_FLOW_OP_DIVL_EAX_T0:
    ifs = "divl_eax_t0";
    break;
  case INFO_FLOW_OP_DIVW_AX_T0:
    ifs = "divw_ax_t0";
    break;
  case INFO_FLOW_OP_ENTER_LEVEL:
    ifs = "enter_level";
    break;
  case INFO_FLOW_OP_FNSTSW_EAX:
    ifs = "fnstsw_eax";
    break;
  case INFO_FLOW_OP_IDIVB_AL_T0:
    ifs = "idivb_al_t0";
    break;
  case INFO_FLOW_OP_IDIVL_EAX_T0:
    ifs = "idivl_eax_t0";
    break;
  case INFO_FLOW_OP_IDIVW_AX_T0:
    ifs = "idivw_ax_t0";
    break;
  case INFO_FLOW_OP_IMULB_AL_T0:
    ifs = "imulb_al_t0";
    break;
  case INFO_FLOW_OP_IMULL_EAX_T0:
    ifs = "imull_eax_t0";
    break;
  case INFO_FLOW_OP_IMULL_T0_T1:
    ifs = "imull_t0_t1";
    break;
  case INFO_FLOW_OP_IMULW_AX_T0:
    ifs = "imulw_ax_t0";
    break;
  case INFO_FLOW_OP_IMULW_T0_T1:
    ifs = "imulw_t0_t1";
    break;
  case INFO_FLOW_OP_INCL_T0:
    ifs = "incl_t0";
    break;
  case INFO_FLOW_OP_INVLPG_A0:
    ifs = "invlpg_a0";
    break;
  case INFO_FLOW_OP_IRET_PROTECTED:
    ifs = "iret_protected";
    break;
  case INFO_FLOW_OP_IRET_REAL:
    ifs = "iret_real";
    break;
  case INFO_FLOW_OP_JMP_T0:
    ifs = "jmp_t0";
    break;
  case INFO_FLOW_OP_LAR:
    ifs = "lar";
    break;
  case INFO_FLOW_OP_LCALL_PROTECTED_T0_T1:
    ifs = "lcall_protected_t0_t1";
    break;
  case INFO_FLOW_OP_LCALL_REAL_T0_T1:
    ifs = "lcall_real_t0_t1";
    break;
  case INFO_FLOW_OP_LJMP_PROTECTED_T0_T1:
    ifs = "ljmp_protected_t0_t1";
    break;
  case INFO_FLOW_OP_LLDT_T0:
    ifs = "lldt_t0";
    break;
  case INFO_FLOW_OP_LMSW_T0:
    ifs = "lmsw_t0";
    break;
  case INFO_FLOW_OP_LRET_PROTECTED:
    ifs = "lret_protected";
    break;
  case INFO_FLOW_OP_LSL:
    ifs = "lsl";
    break;
  case INFO_FLOW_OP_LTR_T0:
    ifs = "ltr_t0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T0_A0:
    ifs = "memsuffix_addr_ldl_t0_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T1_A0:
    ifs = "memsuffix_addr_ldl_t1_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T0_A0:
    ifs = "memsuffix_addr_ldsb_t0_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T1_A0:
    ifs = "memsuffix_addr_ldsb_t1_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T0_A0:
    ifs = "memsuffix_addr_ldsw_t0_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T1_A0:
    ifs = "memsuffix_addr_ldsw_t1_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T0_A0:
    ifs = "memsuffix_addr_ldub_t0_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T1_A0:
    ifs = "memsuffix_addr_ldub_t1_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T0_A0:
    ifs = "memsuffix_addr_lduw_t0_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T1_A0:
    ifs = "memsuffix_addr_lduw_t1_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STB_T0_A0:
    ifs = "memsuffix_addr_stb_t0_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T0_A0:
    ifs = "memsuffix_addr_stl_t0_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T1_A0:
    ifs = "memsuffix_addr_stl_t1_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T0_A0:
    ifs = "memsuffix_addr_stw_t0_a0";
    break;
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T1_A0:
    ifs = "memsuffix_addr_stw_t1_a0";
    break;
  case INFO_FLOW_OP_MOVB_EFLAGS_T0:
    ifs = "movb_eflags_t0";
    break;
  case INFO_FLOW_OP_MOVL_A0_IM:
    ifs = "movl_a0_im";
    break;
  case INFO_FLOW_OP_MOVL_CRN_T0:
    ifs = "movl_crn_t0";
    break;
  case INFO_FLOW_OP_MOVL_DRN_T0:
    ifs = "movl_drn_t0";
    break;
  case INFO_FLOW_OP_MOVL_EFLAGS_T0:
    ifs = "movl_eflags_t0";
    break;
  case INFO_FLOW_OP_MOVL_EFLAGS_T0_CPL0:
    ifs = "movl_eflags_t0_cpl0";
    break;
  case INFO_FLOW_OP_MOVL_EFLAGS_T0_IO:
    ifs = "movl_eflags_t0_io";
    break;
  case INFO_FLOW_OP_MOVL_EIP_IM:
    ifs = "movl_eip_im";
    break;
  case INFO_FLOW_OP_MOVL_SEG_T0:
    ifs = "movl_seg_t0";
    break;
  case INFO_FLOW_OP_MOVL_SEG_T0_VM:
    ifs = "movl_seg_t0_vm";
    break;
  case INFO_FLOW_OP_MOVL_T0_0:
    ifs = "movl_t0_0";
    break;
  case INFO_FLOW_OP_MOVL_T0_EFLAGS:
    ifs = "movl_t0_eflags";
    break;
  case INFO_FLOW_OP_MOVL_T0_IM:
    ifs = "movl_t0_im";
    break;
  case INFO_FLOW_OP_MOVL_T0_IMU:
    ifs = "movl_t0_imu";
    break;
  case INFO_FLOW_OP_MOVL_T0_SEG:
    ifs = "movl_t0_seg";
    break;
  case INFO_FLOW_OP_MOVL_T0_T1:
    ifs = "movl_t0_t1";
    break;
  case INFO_FLOW_OP_MOVL_T1_A0:
    ifs = "movl_t1_a0";
    break;
  case INFO_FLOW_OP_MOVL_T1_IM:
    ifs = "movl_t1_im";
    break;
  case INFO_FLOW_OP_MOVL_T1_IMU:
    ifs = "movl_t1_imu";
    break;
  case INFO_FLOW_OP_MOVSBL_T0_T0:
    ifs = "movsbl_t0_t0";
    break;
  case INFO_FLOW_OP_MOVSBW_AX_AL:
    ifs = "movsbw_ax_al";
    break;
  case INFO_FLOW_OP_MOVSLQ_EDX_EAX:
    ifs = "movslq_edx_eax";
    break;
  case INFO_FLOW_OP_MOVSWL_DX_AX:
    ifs = "movswl_dx_ax";
    break;
  case INFO_FLOW_OP_MOVSWL_EAX_AX:
    ifs = "movswl_eax_ax";
    break;
  case INFO_FLOW_OP_MOVSWL_T0_T0:
    ifs = "movswl_t0_t0";
    break;
  case INFO_FLOW_OP_MOVTL_T0_CR8:
    ifs = "movtl_t0_cr8";
    break;
  case INFO_FLOW_OP_MOVW_EFLAGS_T0:
    ifs = "movw_eflags_t0";
    break;
  case INFO_FLOW_OP_MOVW_EFLAGS_T0_CPL0:
    ifs = "movw_eflags_t0_cpl0";
    break;
  case INFO_FLOW_OP_MOVW_EFLAGS_T0_IO:
    ifs = "movw_eflags_t0_io";
    break;
  case INFO_FLOW_OP_MOVZBL_T0_T0:
    ifs = "movzbl_t0_t0";
    break;
  case INFO_FLOW_OP_MOVZWL_T0_T0:
    ifs = "movzwl_t0_t0";
    break;
  case INFO_FLOW_OP_MOV_T0_CC:
    ifs = "mov_t0_cc";
    break;
  case INFO_FLOW_OP_MULB_AL_T0:
    ifs = "mulb_al_t0";
    break;
  case INFO_FLOW_OP_MULL_EAX_T0:
    ifs = "mull_eax_t0";
    break;
  case INFO_FLOW_OP_MULW_AX_T0:
    ifs = "mulw_ax_t0";
    break;
  case INFO_FLOW_OP_NEGL_T0:
    ifs = "negl_t0";
    break;
  case INFO_FLOW_OP_NOTL_T0:
    ifs = "notl_t0";
    break;
  case INFO_FLOW_OP_ORL_T0_T1:
    ifs = "orl_t0_t1";
    break;
  case INFO_FLOW_OP_RDMSR:
    ifs = "rdmsr";
    break;
  case INFO_FLOW_OP_RDTSC:
    ifs = "rdtsc";
    break;
  case INFO_FLOW_OP_REG_ADDL_A0_R:
    ifs = "reg_addl_a0_r";
    break;
  case INFO_FLOW_OP_REG_ADDL_A0_R_S1:
    ifs = "reg_addl_a0_r_s1";
    break;
  case INFO_FLOW_OP_REG_ADDL_A0_R_S2:
    ifs = "reg_addl_a0_r_s2";
    break;
  case INFO_FLOW_OP_REG_ADDL_A0_R_S3:
    ifs = "reg_addl_a0_r_s3";
    break;
  case INFO_FLOW_OP_REG_CMOVL_R_T1_T0:
    ifs = "reg_cmovl_r_t1_t0";
    break;
  case INFO_FLOW_OP_REG_CMOVW_R_T1_T0:
    ifs = "reg_cmovw_r_t1_t0";
    break;
  case INFO_FLOW_OP_REG_MOVB_R_T0:
    ifs = "reg_movb_r_t0";
    break;
  case INFO_FLOW_OP_REG_MOVB_R_T1:
    ifs = "reg_movb_r_t1";
    break;
  case INFO_FLOW_OP_REG_MOVH_R_T0:
    ifs = "reg_movh_r_t0";
    break;
  case INFO_FLOW_OP_REG_MOVH_R_T1:
    ifs = "reg_movh_r_t1";
    break;
  case INFO_FLOW_OP_REG_MOVH_T0_R:
    ifs = "reg_movh_t0_r";
    break;
  case INFO_FLOW_OP_REG_MOVH_T1_R:
    ifs = "reg_movh_t1_r";
    break;
  case INFO_FLOW_OP_REG_MOVL_A0_R:
    ifs = "reg_movl_a0_r";
    break;
  case INFO_FLOW_OP_REG_MOVL_R_A0:
    ifs = "reg_movl_r_a0";
    break;
  case INFO_FLOW_OP_REG_MOVL_R_T0:
    ifs = "reg_movl_r_t0";
    break;
  case INFO_FLOW_OP_REG_MOVL_R_T1:
    ifs = "reg_movl_r_t1";
    break;
  case INFO_FLOW_OP_REG_MOVL_T0_R:
    ifs = "reg_movl_t0_r";
    break;
  case INFO_FLOW_OP_REG_MOVL_T1_R:
    ifs = "reg_movl_t1_r";
    break;
  case INFO_FLOW_OP_REG_MOVW_R_A0:
    ifs = "reg_movw_r_a0";
    break;
  case INFO_FLOW_OP_REG_MOVW_R_T0:
    ifs = "reg_movw_r_t0";
    break;
  case INFO_FLOW_OP_REG_MOVW_R_T1:
    ifs = "reg_movw_r_t1";
    break;
  case INFO_FLOW_OP_SALC:
    ifs = "salc";
    break;
  case INFO_FLOW_OP_SETBE_T0_CC:
    ifs = "setbe_t0_cc";
    break;
  case INFO_FLOW_OP_SETB_T0_CC:
    ifs = "setb_t0_cc";
    break;
  case INFO_FLOW_OP_SETLE_T0_CC:
    ifs = "setle_t0_cc";
    break;
  case INFO_FLOW_OP_SETL_T0_CC:
    ifs = "setl_t0_cc";
    break;
  case INFO_FLOW_OP_SETO_T0_CC:
    ifs = "seto_t0_cc";
    break;
  case INFO_FLOW_OP_SETP_T0_CC:
    ifs = "setp_t0_cc";
    break;
  case INFO_FLOW_OP_SETS_T0_CC:
    ifs = "sets_t0_cc";
    break;
  case INFO_FLOW_OP_SETZ_T0_CC:
    ifs = "setz_t0_cc";
    break;
  case INFO_FLOW_OP_SHIFT_ADD_BIT_A0_T1:
    ifs = "shift_add_bit_a0_t1";
    break;
  case INFO_FLOW_OP_SHIFT_BSF_T0_CC:
    ifs = "shift_bsf_t0_cc";
    break;
  case INFO_FLOW_OP_SHIFT_BSR_T0_CC:
    ifs = "shift_bsr_t0_cc";
    break;
  case INFO_FLOW_OP_SHIFT_BTC_T0_T1_CC:
    ifs = "shift_btc_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_BTR_T0_T1_CC:
    ifs = "shift_btr_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_BTS_T0_T1_CC:
    ifs = "shift_bts_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_IN_DX_T0:
    ifs = "shift_in_dx_t0";
    break;
  case INFO_FLOW_OP_SHIFT_IN_T0_T1:
    ifs = "shift_in_t0_t1";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ADC_T0_T1_CC:
    ifs = "shift_mem_write_adc_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_CMPXCHG_T0_T1_EAX_CC:
    ifs = "shift_mem_write_cmpxchg_t0_t1_eax_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_RCL_T0_T1_CC:
    ifs = "shift_mem_write_rcl_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_RCR_T0_T1_CC:
    ifs = "shift_mem_write_rcr_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROL_T0_T1:
    ifs = "shift_mem_write_rol_t0_t1";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROL_T0_T1_CC:
    ifs = "shift_mem_write_rol_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROR_T0_T1:
    ifs = "shift_mem_write_ror_t0_t1";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROR_T0_T1_CC:
    ifs = "shift_mem_write_ror_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SAR_T0_T1_CC:
    ifs = "shift_mem_write_sar_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SBB_T0_T1_CC:
    ifs = "shift_mem_write_sbb_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHLD_T0_T1_ECX_CC:
    ifs = "shift_mem_write_shld_t0_t1_ecx_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHLD_T0_T1_IM_CC:
    ifs = "shift_mem_write_shld_t0_t1_im_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHL_T0_T1_CC:
    ifs = "shift_mem_write_shl_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHRD_T0_T1_ECX_CC:
    ifs = "shift_mem_write_shrd_t0_t1_ecx_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHRD_T0_T1_IM_CC:
    ifs = "shift_mem_write_shrd_t0_t1_im_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHR_T0_T1_CC:
    ifs = "shift_mem_write_shr_t0_t1_cc";
    break;
  case INFO_FLOW_OP_SHIFT_MOVL_T0_DSHIFT:
    ifs = "shift_movl_t0_dshift";
    break;
  case INFO_FLOW_OP_SHIFT_SAR_T0_T1:
    ifs = "shift_sar_t0_t1";
    break;
  case INFO_FLOW_OP_SHIFT_SETBE_T0_SUB:
    ifs = "shift_setbe_t0_sub";
    break;
  case INFO_FLOW_OP_SHIFT_SETB_T0_SUB:
    ifs = "shift_setb_t0_sub";
    break;
  case INFO_FLOW_OP_SHIFT_SETLE_T0_SUB:
    ifs = "shift_setle_t0_sub";
    break;
  case INFO_FLOW_OP_SHIFT_SETL_T0_SUB:
    ifs = "shift_setl_t0_sub";
    break;
  case INFO_FLOW_OP_SHIFT_SETS_T0_SUB:
    ifs = "shift_sets_t0_sub";
    break;
  case INFO_FLOW_OP_SHIFT_SETZ_T0_SUB:
    ifs = "shift_setz_t0_sub";
    break;
  case INFO_FLOW_OP_SHIFT_SHL_T0_T1:
    ifs = "shift_shl_t0_t1";
    break;
  case INFO_FLOW_OP_SHIFT_SHR_T0_T1:
    ifs = "shift_shr_t0_t1";
    break;
  case INFO_FLOW_OP_SUBL_A0_2:
    ifs = "subl_a0_2";
    break;
  case INFO_FLOW_OP_SUBL_A0_4:
    ifs = "subl_a0_4";
    break;
  case INFO_FLOW_OP_SUBL_T0_T1:
    ifs = "subl_t0_t1";
    break;
  case INFO_FLOW_OP_SYSENTER:
    ifs = "sysenter";
    break;
  case INFO_FLOW_OP_SYSEXIT:
    ifs = "sysexit";
    break;
  case INFO_FLOW_OP_WRMSR:
    ifs = "wrmsr";
    break;
  case INFO_FLOW_OP_XORL_T0_T1:
    ifs = "xorl_t0_t1";
    break;
  case INFO_FLOW_OP_XOR_T0_1:
    ifs = "xor_t0_1";
    break;
  case INFO_FLOW_OP_KEYBOARD_INPUT:
    ifs = "keyboard_input";
    break;
  case INFO_FLOW_OP_NEW_KEYBOARD_LABEL:
    ifs = "new_keyboard_label";
    break;
 case INFO_FLOW_OP_NEW_NETWORK_LABEL:
    ifs = "new_network_label";
    break;
  case INFO_FLOW_OP_NETWORK_INPUT_BYTE_T0:
    ifs = "network_input_byte_T0";
    break;
  case INFO_FLOW_OP_NETWORK_INPUT_WORD_T0:
    ifs = "network_input_word_T0";
    break;
  case INFO_FLOW_OP_NETWORK_INPUT_LONG_T0:
    ifs = "network_input_long_T0";
    break;
  case INFO_FLOW_OP_NETWORK_INPUT_BYTE_T1:
    ifs = "network_input_byte_T1";
    break;
  case INFO_FLOW_OP_NETWORK_INPUT_WORD_T1:
    ifs = "network_input_word_T1";
    break;
  case INFO_FLOW_OP_NETWORK_INPUT_LONG_T1:
    ifs = "network_input_long_T1";
    break;
  case INFO_FLOW_OP_NETWORK_OUTPUT_BYTE_T0:
    ifs = "network_output_byte_T0";
    break;
  case INFO_FLOW_OP_NETWORK_OUTPUT_WORD_T0:
    ifs = "network_output_word_T0";
    break;
  case INFO_FLOW_OP_NETWORK_OUTPUT_LONG_T0:
    ifs = "network_output_long_T0";
    break;
  case INFO_FLOW_OP_NETWORK_OUTPUT_BYTE_T1:
    ifs = "network_output_byte_T1";
    break;
  case INFO_FLOW_OP_NETWORK_OUTPUT_WORD_T1:
    ifs = "network_output_word_T1";
    break;
  case INFO_FLOW_OP_NETWORK_OUTPUT_LONG_T1:
    ifs = "network_output_long_T1";
    break;
  case INFO_FLOW_OP_HD_TRANSFER:
    ifs = "hd_transfer";
    break;
  case INFO_FLOW_OP_HD_TRANSFER_PART1:
    ifs = "hd_transfer_part1";
    break;
  case INFO_FLOW_OP_HD_TRANSFER_PART2:
    ifs = "hd_transfer_part2";
    break;
  case INFO_FLOW_OP_X86_INSN:
    ifs = "X86_insn";
    break;
  case INFO_FLOW_OP_CMPXCHG_T0_T1_EAX_CC_CASE1:
    ifs = "cmpxchg_t0_t1_eax_cc_case1";
    break;
  case INFO_FLOW_OP_CMPXCHG_T0_T1_EAX_CC_CASE2:
    ifs = "cmpxchg_t0_t1_eax_cc_case2";
    break;
  case INFO_FLOW_OP_CMPXCHG_T0_T1_EAX_CC_CASE3:
    ifs = "cmpxchg_t0_t1_eax_cc_case3";
    break;
  case INFO_FLOW_OP_SAVE_REG:
    ifs = "save_reg";
    break;
  case INFO_FLOW_OP_RESTORE_REG:
    ifs = "restore_reg";
    break;
  case INFO_FLOW_OP_CPU_READ_ADDR:
    ifs = "cpu_read_addr";
    break;
  case INFO_FLOW_OP_CPU_WRITE_ADDR:
    ifs = "cpu_write_addr";
    break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDQ:
	ifs = "mmu_phys_addr_direct_ldq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDL:
	ifs = "mmu_phys_addr_direct_ldl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDW:
	ifs = "mmu_phys_addr_direct_ldw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDB:
	ifs = "mmu_phys_addr_direct_ldb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDQ:
	ifs = "mmu_phys_addr_io_aligned_ldq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDL:
	ifs = "mmu_phys_addr_io_aligned_ldl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDW:
	ifs = "mmu_phys_addr_io_aligned_ldw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDB:
	ifs = "mmu_phys_addr_io_aligned_ldb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDQ:
	ifs = "mmu_phys_addr_unaligned_same_page_ldq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDL:
	ifs = "mmu_phys_addr_unaligned_same_page_ldl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDB:
	ifs = "mmu_phys_addr_unaligned_same_page_ldb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDW:
	ifs = "mmu_phys_addr_unaligned_same_page_ldw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDQ:
	ifs = "mmu_phys_addr_unaligned_differnt_page_part1_ldq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDL:
	ifs = "mmu_phys_addr_unaligned_differnt_page_part1_ldl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDW:
	ifs = "mmu_phys_addr_unaligned_differnt_page_part1_ldw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDB:
	ifs = "mmu_phys_addr_unaligned_differnt_page_part1_ldb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDQ:
	ifs = "mmu_phys_addr_unaligned_differnt_page_part2_ldq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDL:
	ifs = "mmu_phys_addr_unaligned_differnt_page_part2_ldl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDB:
	ifs = "mmu_phys_addr_unaligned_differnt_page_part2_ldb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDW:
	ifs = "mmu_phys_addr_unaligned_differnt_page_part2_ldw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDQ:
	ifs = "mmu_phys_addr_unaligned_differnt_page_io_part2_ldq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDL:
	ifs = "mmu_phys_addr_unaligned_differnt_page_io_part2_ldl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDB:
	ifs = "mmu_phys_addr_unaligned_differnt_page_io_part2_ldb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDW:
	ifs = "mmu_phys_addr_unaligned_differnt_page_io_part2_ldw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STQ:
	ifs = "mmu_phys_addr_direct_stq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STL:
	ifs = "mmu_phys_addr_direct_stl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STW:
	ifs = "mmu_phys_addr_direct_stw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STB:
	ifs = "mmu_phys_addr_direct_stb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STQ:
	ifs = "mmu_phys_addr_io_aligned_stq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STL:
	ifs = "mmu_phys_addr_io_aligned_stl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STW:
	ifs = "mmu_phys_addr_io_aligned_stw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STB:
	ifs = "mmu_phys_addr_io_aligned_stb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STQ:
	ifs = "mmu_phys_addr_unaligned_same_page_stq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STL:
	ifs = "mmu_phys_addr_unaligned_same_page_stl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STB:
	ifs = "mmu_phys_addr_unaligned_same_page_stb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STW:
	ifs = "mmu_phys_addr_unaligned_same_page_stw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STQ:
	ifs = "mmu_phys_addr_unaligned_different_page_part1_stq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STL:
	ifs = "mmu_phys_addr_unaligned_different_page_part1_stl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STW:
	ifs = "mmu_phys_addr_unaligned_different_page_part1_stw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STB:
	ifs = "mmu_phys_addr_unaligned_different_page_part1_stb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STQ:
	ifs = "mmu_phys_addr_unaligned_different_page_part2_stq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STL:
	ifs = "mmu_phys_addr_unaligned_different_page_part2_stl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STB:
	ifs = "mmu_phys_addr_unaligned_different_page_part2_stb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STW:
	ifs = "mmu_phys_addr_unaligned_different_page_part2_stw";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STQ:
	ifs = "mmu_phys_addr_unaligned_different_page_io_part2_stq";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STL:
	ifs = "mmu_phys_addr_unaligned_different_page_io_part2_stl";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STB:
	ifs = "mmu_phys_addr_unaligned_different_page_io_part2_stb";
	break;
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STW:
	ifs = "mmu_phys_addr_unaligned_different_page_io_part2_stw";
	break;
  case INFO_FLOW_OP_TLB_FILL:
	ifs = "tlb_fill";
	break;	
  case INFO_FLOW_OP_SAVE_ENV:
	ifs="save_env";
	break;
  case INFO_FLOW_OP_RESTORE_ENV:
	ifs="restore_env";
	break;

  default:
    ifs ="WTF_MATE";
  }
  return ifs;
}


char *if_reg_str(int if_regnum) {
  return (info_flow_reg_str[if_regnum]);
}


void timer_reset (void) {
  gettimeofday(&last_time, NULL);
}


double timer_time () {
  struct timeval this_time;
  gettimeofday(&this_time, NULL);
  return (this_time.tv_sec - last_time.tv_sec
	  + (this_time.tv_usec - last_time.tv_usec)/1.0e6);
}


void if_debug_set(int l) {
  if_debug = l;
}


void if_debug_set_off() {
  if_debug = IF_DEBUG_OFF;
}


void if_debug_set_low() {
  if_debug = IF_DEBUG_LOW;
}


void if_debug_set_med() {
  if_debug = IF_DEBUG_MED;
}


void if_debug_set_high() {
  if_debug = IF_DEBUG_HIGH;
}


void if_debug_set_omg() {
  if_debug = IF_DEBUG_OMG;
}


trl_boolean debug_off() {
  return (if_debug == IF_DEBUG_OFF);
}


trl_boolean debug_low() {
  return (if_debug <= IF_DEBUG_LOW);
}


trl_boolean debug_med() {
  return (if_debug <= IF_DEBUG_MED);
}


trl_boolean debug_high() {
  return (if_debug <= IF_DEBUG_HIGH);
}


trl_boolean debug_omg() {
  return (if_debug <= IF_DEBUG_OMG);
}


trl_boolean debug_at_least_low() {
  return (if_debug >= IF_DEBUG_LOW);
}


trl_boolean debug_at_least_med() {
  return (if_debug >= IF_DEBUG_MED);
}


trl_boolean debug_at_least_high() {
  return (if_debug >= IF_DEBUG_HIGH);
}


trl_boolean debug_at_least_omg() {
  return (if_debug >= IF_DEBUG_OMG);
}


void if_save_log_on() {
  if_save_log = TRUE;
}


void if_save_log_off() {
  if_save_log = FALSE;
}


// used by qsort
int hist_comp(const void *p1, const void *p2) {
  int i1, i2;
  i1 = *((int *) p1);
  i2 = *((int *) p2);
  if (if_op_hist[i1]<if_op_hist[i2]) return 1;
  if (if_op_hist[i1]>if_op_hist[i2]) return -1;
  return 0;
}


void if_show_hist() {
  int i;
  int si[256];
  float sum = 0.0;

  for (i=0; i<256; i++) {
    si[i] = i;
    sum += if_op_hist[i];
  }
  qsort(si, 256, sizeof(int), hist_comp);

  printf ("\n");
  for (i=0; i<256; i++) {
    int j = si[i];
    if (if_op_hist[j] > 0) 
      printf ("%6d %10d %.3f %s\n", j, if_op_hist[j], if_op_hist[j] / sum, if_op_str(j));
  }
}


// this gets called from the qemu monitor in order to 
// change the current keyboard label
void if_set_keyboard_label(const char *label) {
  if (if_keyboard_label == NULL) 
    if_keyboard_label = (char *) my_malloc(IF_MAX_KEYBOARD_LABEL_LEN);
  printf ("if_set_keyboard_label: label is henceforth [%s]\n", label);
  strncpy(if_keyboard_label, label, IF_MAX_KEYBOARD_LABEL_LEN);
  if_keyboard_label_changed = TRUE;
}

// this gets called from the qemu monitor in order to 
// change the current network label
void if_set_network_label(const char *label) {
  if (if_network_label == NULL) 
    if_network_label = (char *) my_malloc(IF_MAX_NETWORK_LABEL_LEN);
  printf ("if_set_network_label: label is henceforth [%s]\n", label);
  strncpy(if_network_label, label, IF_MAX_NETWORK_LABEL_LEN);
  if_network_label_changed = TRUE;
}






void if_log_create() {
  uint32_t i; 
  printf ("if_log_create\n");
  if_set_keyboard_label("keyboard_startup");
  if_set_network_label("network_startup");
  // set up ifregaddr array.
  for (i=0; i<16; i++) {

    // all addresses memory addresses will be on the interval 
    // 0 .. phys_ram_size-1.  
    // We'll pretend the registers live starting at phys_ram_size.
    // and we'll make them 8 bytes just for fun.
    ifregaddr[i] = (unsigned long long) ( ((uint64_t) phys_ram_size) + i*8);
    printf("Register i=%d is at 0x%p\r\n",i, (char *)ifregaddr[i]);
  }
  if (debug_at_least_low()) 
    printf ("if_log_create\n");
  // initial info flow log allocation.
  if_log_len = IF_LOG_SIZE;
  // why 1.5?  
  if_log_ptr = if_log_base = (char *) my_calloc ((int) (if_log_len * 1.5), 1);
  { 
    int i;
    for (i=0; i<if_log_len; i++) if_log_ptr[i] = 0xff;
  }
  if (if_count_ops == TRUE) {
    int i;
    for (i=0; i<256; i++) 
      if_op_hist[i] = 0;
  }
  //  loglog_fp = fopen("loglog", "w");

  if (debug_at_least_high()) {
    printf ("EAX is at %Lux\n", IFRBA(IFRN_EAX)); // 0x0
    printf ("ECX is at %Lux\n", IFRBA(IFRN_ECX)); // 0x8
    printf ("EDX is at %Lux\n", IFRBA(IFRN_EDX)); // 0x10
    printf ("EBX is at %Lux\n", IFRBA(IFRN_EBX)); // 0x18
    printf ("ESP is at %Lux\n", IFRBA(IFRN_ESP)); // 0x20
    printf ("EBP is at %Lux\n", IFRBA(IFRN_EBP)); // 0x28
    printf ("ESI is at %Lux\n", IFRBA(IFRN_ESI)); // 0x30
    printf ("EDI is at %Lux\n", IFRBA(IFRN_EDI)); // 0x38
    printf ("T0 is at %Lux\n", IFRBA(IFRN_T0));   // 0x40
    printf ("T1 is at %Lux\n", IFRBA(IFRN_T1));   // 0x48
    printf ("A0 is at %Lux\n", IFRBA(IFRN_A0));   // 0x50
    printf ("Q0 is at %Lux\n", IFRBA(IFRN_Q0));   // 0x58
    printf ("Q1 is at %Lux\n", IFRBA(IFRN_Q1));   // 0x60
    printf ("Q2 is at %Lux\n", IFRBA(IFRN_Q2));   // 0x68
    printf ("Q3 is at %Lux\n", IFRBA(IFRN_Q3));   // 0x70
    printf ("Q4 is at %Lux\n", IFRBA(IFRN_Q4));   // 0x78
  }
  printf("exiting log_create\r\n");
}



void if_log_destroy() {
  fclose(loglog_fp);
}



// p is an address that came out of the log.  
// or it might be a fake address, like a register.
// decide which and print something approriate. 
void render_address(unsigned long long p) {
  if (p == IFRBA(IFRN_EAX)) 
    printf ("&eax");
  else if (p == IFRBA(IFRN_ECX)) 
    printf ("&ecx");
  else if (p == IFRBA(IFRN_EDX)) 
    printf ("&edx");
  else if (p == IFRBA(IFRN_EBX)) 
    printf ("&ebx");
  else if (p == IFRBA(IFRN_ESP)) 
    printf ("&esp");
  else if (p == IFRBA(IFRN_EBP))
    printf ("&ebp");
  else if (p == IFRBA(IFRN_ESI)) 
    printf ("&esi");
  else if (p == IFRBA(IFRN_EDI)) 
    printf ("&edi");
  else if (p == IFRBA(IFRN_T0)) 
    printf ("&t0");
  else if (p == IFRBA(IFRN_T1)) 
    printf ("&t1");
  else if (p == IFRBA(IFRN_A0)) 
    printf ("&a0");
  else if (p == IFRBA(IFRN_Q0)) 
    printf ("&q0");
  else if (p == IFRBA(IFRN_Q1)) 
    printf ("&q1");
  else if (p == IFRBA(IFRN_Q2)) 
    printf ("&q2");
  else if (p == IFRBA(IFRN_Q3)) 
    printf ("&q3");
  else if (p == IFRBA(IFRN_Q4)) 
    printf ("&q4");
  else 
    printf ("0x%Lux",p);
}


// returns TRUE iff address is *not* to a QEMU temporary register
trl_boolean addr_is_real(unsigned long long p) {
  if ((p == IFRBA(IFRN_T0))
      || (p == IFRBA(IFRN_T1)) 
      || (p == IFRBA(IFRN_A0)) 
      || (p == IFRBA(IFRN_Q0)) 
      || (p == IFRBA(IFRN_Q1)) 
      || (p == IFRBA(IFRN_Q2)) 
      || (p == IFRBA(IFRN_Q3)) 
      || (p == IFRBA(IFRN_Q4)))
    return FALSE;
  else 
    return TRUE;
}


// true iff this info-flow op comes from opreg_template.h
inline trl_boolean info_flow_from_opreg_template_dot_h(if_op_t if_op) {
  switch (if_op) {
  case INFO_FLOW_OP_REG_MOVL_A0_R: 
  case INFO_FLOW_OP_REG_ADDL_A0_R: 
  case INFO_FLOW_OP_REG_ADDL_A0_R_S1:
  case INFO_FLOW_OP_REG_ADDL_A0_R_S2:
  case INFO_FLOW_OP_REG_ADDL_A0_R_S3:
  case INFO_FLOW_OP_REG_MOVL_T0_R:
  case INFO_FLOW_OP_REG_MOVL_T1_R:
  case INFO_FLOW_OP_REG_MOVH_T0_R:
  case INFO_FLOW_OP_REG_MOVH_T1_R:
  case INFO_FLOW_OP_REG_MOVL_R_T0:
  case INFO_FLOW_OP_REG_MOVL_R_T1:
  case INFO_FLOW_OP_REG_MOVL_R_A0:
  case INFO_FLOW_OP_REG_CMOVW_R_T1_T0:
  case INFO_FLOW_OP_REG_CMOVL_R_T1_T0:
  case INFO_FLOW_OP_REG_MOVW_R_T0:
  case INFO_FLOW_OP_REG_MOVW_R_T1:
  case INFO_FLOW_OP_REG_MOVW_R_A0:
  case INFO_FLOW_OP_REG_MOVB_R_T0:
  case INFO_FLOW_OP_REG_MOVH_R_T0:
  case INFO_FLOW_OP_REG_MOVB_R_T1:
  case INFO_FLOW_OP_REG_MOVH_R_T1:
    return (TRUE);
  }
  return (FALSE);
}

//true iff this info flow op comes from softmmu_header.h or softmmu_template.h
inline trl_boolean info_flow_op_from_softmmu(if_op_t if_op){
  switch(if_op) {
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STW:
    return(TRUE);
  }
  return(FALSE);
}

//true iff this info flow op comes from softmmu_header.h and has a byte arg
inline trl_boolean info_flow_op_from_softmmu_and_has_byte_arg(if_op_t if_op){
  switch(if_op) {
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STW:
    return(TRUE);
  }
  return(FALSE);
}


//true iff this info-flow op is an mmu load address
inline trl_boolean info_flow_op_is_mmu_load_addr(if_op_t if_op){
  switch(if_op){
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDW:
  return(TRUE); 
  }
  return(FALSE);
}

//true iff this info-flow op is an mmu store address
inline trl_boolean info_flow_op_is_mmu_store_addr(if_op_t if_op){
  switch(if_op){
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STW:
  return(TRUE); 
  }
  return(FALSE);
}
//true iff this info-flow op is an mmu long long address
inline trl_boolean info_flow_op_is_mmu_long_long_type(if_op_t if_op){
  switch(if_op){
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STQ:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STQ:
    return(TRUE);
  }
  return(FALSE);
}

//true iff this info-flow op is an mmu long address
inline trl_boolean info_flow_op_is_mmu_long_type(if_op_t if_op){
  switch(if_op){
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STL:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STL:
    return(TRUE);
  }
  return(FALSE);
}

//true iff this info-flow op is an mmu word address
inline trl_boolean info_flow_op_is_mmu_word_type(if_op_t if_op){
  switch(if_op){
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STW:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STW:
    return(TRUE);
  }
  return(FALSE);
}

//true iff this info-flow op is an mmu byte address
inline trl_boolean info_flow_op_is_mmu_byte_type(if_op_t if_op){
  switch(if_op){
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_LDB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_DIRECT_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_IO_ALIGNED_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_SAME_PAGE_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART1_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_PART2_STB:
  case INFO_FLOW_OP_MMU_PHYS_ADDR_UNALIGNED_DIFFERENT_PAGE_IO_PART2_STB:
    return(TRUE);
  }
  return(FALSE);
}

//true iff this info_flow op is a load op
inline trl_boolean info_flow_is_load_op(if_op_t if_op) {
  switch (if_op) {
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T1_A0:
    return (TRUE);
  }
  return (FALSE);
}
//true iff this info_flow op is a store op
inline trl_boolean info_flow_is_store_op(if_op_t if_op) {
  switch (if_op) {
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STB_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T1_A0:
    return (TRUE);
  }
  return (FALSE);
}
//true iff this info_flow op is a byte ldst op
inline trl_boolean info_flow_is_ldst_byte_op(if_op_t if_op) {
  switch (if_op) {
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STB_T0_A0:
    return (TRUE);
  }
  return (FALSE);
}

//true iff this info_flow op is a ldst word op 
inline trl_boolean info_flow_is_ldst_word_op(if_op_t if_op) {
  switch (if_op) {
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T1_A0:
    return (TRUE);
  }
  return (FALSE);
}

//true iff this info_flow op is a ldst long op 
inline trl_boolean info_flow_is_ldst_long_op(if_op_t if_op) {
  switch (if_op) {
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T1_A0:
    return (TRUE);
  }
  return (FALSE);
}

// true iff this info-flow op comes from ops_mem.h
inline trl_boolean info_flow_from_ops_mem_dot_h(if_op_t if_op) {
  switch (if_op) {
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STB_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T0_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T1_A0:
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T1_A0:
    return (TRUE);
  }
  return (FALSE);
}

    
// true iff this info-flow op comes from ops_template.h
inline trl_boolean info_flow_from_ops_template_dot_h(if_op_t if_op) {
  switch (if_op) {
  case INFO_FLOW_OP_SHIFT_SETB_T0_SUB:
  case INFO_FLOW_OP_SHIFT_SETZ_T0_SUB:
  case INFO_FLOW_OP_SHIFT_SETBE_T0_SUB:
  case INFO_FLOW_OP_SHIFT_SETS_T0_SUB:
  case INFO_FLOW_OP_SHIFT_SETL_T0_SUB:
  case INFO_FLOW_OP_SHIFT_SETLE_T0_SUB:
  case INFO_FLOW_OP_SHIFT_SHL_T0_T1:
  case INFO_FLOW_OP_SHIFT_SHR_T0_T1:
  case INFO_FLOW_OP_SHIFT_SAR_T0_T1:
  case INFO_FLOW_OP_SHIFT_BTS_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_BTR_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_BTC_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_ADD_BIT_A0_T1:
  case INFO_FLOW_OP_SHIFT_BSF_T0_CC:
  case INFO_FLOW_OP_SHIFT_BSR_T0_CC:
  case INFO_FLOW_OP_SHIFT_MOVL_T0_DSHIFT:
  case INFO_FLOW_OP_SHIFT_IN_T0_T1:
  case INFO_FLOW_OP_SHIFT_IN_DX_T0:
    return (TRUE);
  }
  return (FALSE);
}


// true iff this info-flow op comes from ops_template_mem.h
inline trl_boolean info_flow_from_ops_template_mem_dot_h(if_op_t if_op) {
  switch(if_op) {
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROL_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROR_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROL_T0_T1:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROR_T0_T1:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_RCL_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_RCR_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHL_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHR_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SAR_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHLD_T0_T1_IM_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHLD_T0_T1_ECX_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHRD_T0_T1_IM_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHRD_T0_T1_ECX_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ADC_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SBB_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_CMPXCHG_T0_T1_EAX_CC:
    return (TRUE);
  }
  return (FALSE);
}


// true iff this info-flow op comes with an argument
inline trl_boolean info_flow_takes_an_arg(if_op_t if_op) {
  return (info_flow_from_opreg_template_dot_h(if_op) 
	  || info_flow_from_ops_mem_dot_h(if_op) 
	  || info_flow_from_ops_template_dot_h(if_op)
	  || info_flow_from_ops_template_mem_dot_h(if_op)
          || if_op == INFO_FLOW_OP_SAVE_REG);  
}


// true iff this info-flow op comes with an address
inline trl_boolean info_flow_takes_an_addr(if_op_t if_op) {
  switch (if_op) {
  case INFO_FLOW_OP_ADDR_MOVL_A0_SEG:
  case INFO_FLOW_OP_ADDR_ADDL_A0_SEG:
  case INFO_FLOW_OP_ADDR_MOVL_T0_ENV:
  case INFO_FLOW_OP_ADDR_MOVL_ENV_T0:
  case INFO_FLOW_OP_ADDR_MOVL_ENV_T1:
  case INFO_FLOW_OP_ADDR_MOVTL_T0_ENV:
  case INFO_FLOW_OP_ADDR_MOVTL_ENV_T0:
  case INFO_FLOW_OP_ADDR_MOVTL_T1_ENV:
  case INFO_FLOW_OP_ADDR_MOVTL_ENV_T1:
    return (TRUE);
  }
  return (FALSE);
}


// true iff this info-flow op comes with a regnum
inline trl_boolean info_flow_takes_regnum(if_op_t if_op) {
  return (info_flow_from_opreg_template_dot_h(if_op) || if_op == INFO_FLOW_OP_SAVE_REG);
}


inline trl_boolean info_flow_takes_memsuffixnum(if_op_t if_op) {
  return (info_flow_from_ops_mem_dot_h(if_op));
}


inline trl_boolean info_flow_takes_shift_only(if_op_t if_op) {
  return 
    (((info_flow_from_ops_template_dot_h(if_op)) == TRUE)
     && 
     ((info_flow_from_ops_template_mem_dot_h(if_op)) == FALSE));
}


inline trl_boolean info_flow_takes_shift_and_mem_write(if_op_t if_op) {
  return (info_flow_from_ops_template_mem_dot_h(if_op));
}


// mark this register as possibly tainted
inline void info_flow_mark_as_possibly_tainted (if_regnum_t if_regnum) {
  if_reg_taint[if_regnum] = TRUE;
}


// mark this register and not possibly tainted
inline void info_flow_mark_as_not_possibly_tainted (if_regnum_t if_regnum) {
  if_reg_taint[if_regnum] = FALSE;
}


// should return TRUE if this reg might be tainted. 
//inline trl_boolean info_flow_possibly_tainted (if_regnum_t if_regnum) {
//  return (if_reg_taint[if_regnum] == TRUE);
//}

inline trl_boolean info_flow_possibly_tainted (if_regnum_t if_regnum) {
  return (TRUE);
}




// should return TRUE only if this register cannot be tainted. 
inline trl_boolean info_flow_not_possibly_tainted (if_regnum_t if_regnum) {
  return (if_reg_taint[if_regnum] == FALSE);
}


inline uint64_t ctull(unsigned long long p) {
  return (uint64_t) p;
}


inline uint64_t wctull(unsigned long long p) {
  uint64_t lp;
  //  char key[9];

  lp = ctull(p);

  /*
  memset (key,0,16);
  key[0] = (lp & 0xFF00000000000000) >> 56;
  key[1] = (lp & 0x00FF000000000000) >> 48;
  key[2] = (lp & 0x0000FF0000000000) >> 40;
  key[3] = (lp & 0x000000FF00000000) >> 32;
  key[4] = (lp & 0x00000000FF000000) >> 24;
  key[5] = (lp & 0x0000000000FF0000) >> 16;
  key[6] = (lp & 0x000000000000FF00) >> 8;
  key[7] = (lp & 0x00000000000000FF);
  *((uint64_t *) key) = lp;  
  
  if (tmh == NULL) 
    tmh = vslht_new();
  vslht_add(tmh, key, 1);
  */

  return (lp);
}



void loglog_label(unsigned long long p, uint32_t l, uint32_t n) {
  uint8_t op = 0;
  fwrite(&op, sizeof(op), 1, loglog_fp);
  fwrite(&p, sizeof(p), 1, loglog_fp);
  fwrite(&l, sizeof(l), 1, loglog_fp);
  fwrite(&n, sizeof(n), 1, loglog_fp);
}


void loglog_delete(unsigned long long p, uint32_t n) {
  uint8_t op = 1;
  fwrite(&op, sizeof(op), 1, loglog_fp);
  fwrite(&p, sizeof(p), 1, loglog_fp);
  fwrite(&n, sizeof(n), 1, loglog_fp);
}


void loglog_copy(unsigned long long p1, unsigned long long p2, uint32_t n) {
  uint8_t op = 2;
  fwrite(&op, sizeof(op), 1, loglog_fp);
  fwrite(&p1, sizeof(p1), 1, loglog_fp);
  fwrite(&p2, sizeof(p2), 1, loglog_fp);
  fwrite(&n, sizeof(n), 1, loglog_fp);
}


void loglog_compute(unsigned long long p1, unsigned long long p2, uint32_t n1, uint32_t n2) {
  uint8_t op = 3;
  fwrite(&op, sizeof(op), 1, loglog_fp);
  fwrite(&p1, sizeof(p1), 1, loglog_fp);
  fwrite(&p2, sizeof(p2), 1, loglog_fp);
  fwrite(&n1, sizeof(n1), 1, loglog_fp);
  fwrite(&n2, sizeof(n2), 1, loglog_fp);
}


/*
  These should be the only functions that call the taint library
if_self*/


// check that an if_reg_taint flag is in agreement with the taint graph
void check_reg_taint(if_regnum_t if_regnum, char *file, int line) {

  /*  if (if_reg_taint[if_regnum] == TRUE) {
    // we think the register *may* be tainted.
    // we don't care if it really is.
  }
  else {
    // we think this register cannot possibly be tainted. 
    // need to check. 
    if ((exists_taint(wctull(IFRBA(if_regnum)),4,__FILE__,__LINE__)) == TRUE) {
      // taint graph thinks this register is tainted. 
      // that's a big problem.  
      printf ("check_reg_taint failed. if_reg_taint==FALSE but exist_taint==TRUE!\n");
      printf ("call_site = %s:%d\n", file, line);          
    }
  }
  */
}


// delete info-flow for (p,p+n-1)
inline void info_flow_delete(unsigned long long p, size_t n) {
  trl_boolean was_tainted = FALSE;

  if(foo2 && exists_taint(p,n,__FILE__,__LINE__) && exists_taint_with_label(p,n,"key-keyboard_startup-2-2e",__FILE__,__LINE__))
	printf("DELETING: taint from keyboard label 2-2e with p=%lld n=%d\r\n",p,n);


  if (debug_at_least_med()) {
    printf ("    info_flow_delete (p=");
    render_address(p);
    printf (") (n=%ud)\n", (uint32_t) n);
    was_tainted = exists_taint(wctull(p),n,__FILE__,__LINE__);
    if (foo && was_tainted
	&& (exists_taint_with_label(wctull(p),n, "key-startup-0-2c", __FILE__,__LINE__)))
      printf ("    was tainted with 0-2c\n");
  }
  delete_taint(wctull(p),n,"NONE",-1);
  if (loglog==TRUE) {
    loglog_delete(p,n);
  }
  delete_taint_count ++;
  if (debug_at_least_med()) {
    // make sure it really is untainted now
    trl_boolean is_tainted = exists_taint(wctull(p),n,__FILE__,__LINE__);
    printf ("\twas_tainted=%d is_tainted=%d\n", was_tainted, is_tainted);
    assert (is_tainted == FALSE);
  }
}


// copy of (p2,p2+n-1) to (p1,p1+n-1)
inline void info_flow_copy(unsigned long long p1,unsigned long long p2, size_t n) {

  if(label_taint_count >=1){
  trl_boolean from_was_tainted=FALSE,to_was_tainted=FALSE;

  if(p1 > 0xffff000000000000 && exists_taint(p2,n,__FILE__,__LINE__)){
	printf("Just like dis big one right here! addr:%llu\r\n",p1);
  }
 
  if (debug_at_least_med()) {
    printf ("    info_flow_copy (to=");
    render_address(p1);
    printf (") from=(");
    render_address(p2);
    printf (") (n=%ud)\n", (uint32_t) n);
    from_was_tainted = exists_taint(wctull(p2),n,__FILE__,__LINE__);
    to_was_tainted = exists_taint(wctull(p1),n,__FILE__,__LINE__);
    printf ("    from_was_tainted=%d to_was_tainted=%d\n",
	    from_was_tainted, to_was_tainted);
    if (foo && from_was_tainted
	&& (exists_taint_with_label(wctull(p2),n, "key-startup-0-2c", __FILE__,__LINE__)))
      printf ("    from was tainted with 2c\n");
    if (foo && to_was_tainted
	&& (exists_taint_with_label(wctull(p1),n, "key-startup-0-2c", __FILE__,__LINE__)))
      printf ("    to was tainted with 2c\n");
  }  
  
  if(foo2 && exists_taint(p1,n,__FILE__,__LINE__) && exists_taint_with_label(p1,n,"key-keyboard_startup-2-2e",__FILE__,__LINE__))
	printf("COPYING: taint over keyboard label 2-2e with p=%lld n=%d\r\n",p1,n);
  transfer_taint(wctull(p1),n,wctull(p2),n,1,1,"NONE","NONE",-1);
  if (loglog==TRUE) {
    loglog_copy(p1,p2,n);
  }
  copy_taint_count ++;  
  // no reason to print anything unless from range was tainted
  // which means we'll be transferring taint, or if to range is
  // tainted, which means we'll be untainting
  if (debug_at_least_med()) {
    trl_boolean to_now_tainted = exists_taint(wctull(p1),n,__FILE__,__LINE__);
    printf ("    to_now_tainted=%d\n",
	    to_now_tainted);
    if (foo && to_now_tainted 
	&& (exists_taint_with_label(wctull(p1),n, "key-startup-0-2c", __FILE__,__LINE__)))
      printf ("    to now tainted with 2c\n");
  }
}
}


// a non-obliting compute transfer.
// from (p2,p2+n2-1) to (p1,p1+n1-1)
inline void info_flow_compute(unsigned long long p1, size_t n1, unsigned long long p2, size_t n2) {
  trl_boolean from_was_tainted, to_was_tainted;
  from_was_tainted=FALSE;
  to_was_tainted=FALSE;
  trl_boolean was_there = FALSE;

if(label_taint_count >=1){
  if (debug_at_least_med()) {
    printf ("    info_flow_compute (to=");
    render_address(p1);
    printf (") (n1=%d) (from=", (uint32_t) n1);
    render_address(p2);
    printf (") (n2=%d)\n", (uint32_t) n2);
    from_was_tainted = exists_taint(wctull(p2),n2,__FILE__,__LINE__);
    to_was_tainted = exists_taint(wctull(p1),n1,__FILE__,__LINE__);
    printf ("    from_was_tainted=%d to_was_tainted=%d\n",
	    from_was_tainted, to_was_tainted);
    if (foo && from_was_tainted
	&& (exists_taint_with_label(wctull(p2),n2, "key-startup-0-2c", __FILE__,__LINE__)))
      printf ("    from was tainted with 2c\n");
    if (foo && to_was_tainted
	&& (exists_taint_with_label(wctull(p1),n1, "key-startup-0-2c", __FILE__,__LINE__)))
      printf ("    to was tainted with 2c\n");
  }

  if(foo2 && exists_taint(p1,n1,__FILE__,__LINE__) && exists_taint_with_label(p1,n1,"key-keyboard_startup-2-2e",__FILE__,__LINE__)) { 
	printf("COMPUTING: taint over keyboard label 2-2e with p=%lld n=%d\r\n",p1,n1);
        was_there = TRUE;
  }
  transfer_taint(wctull(p1),n1,wctull(p2),n2,0,0,"NONE","NONE",-1);
  if(was_there && foo2 && exists_taint(p1,n1,__FILE__,__LINE__) && exists_taint_with_label(p1,n1,"key-keyboard_startup-2-2e",__FILE__,__LINE__))
	printf("COMPUTING: yup, taint still there!\r\n");
  if (loglog==TRUE) {
    loglog_compute(p1,p2,n1,n2);
  }
  compute_taint_count ++;
  // Note, this is non-oblitting compute transfer. 
  // so no need to print anything unless from range was tainted
  // since that will propagate a label. 
  if (debug_at_least_med()) {
    trl_boolean to_is_tainted = exists_taint(wctull(p1),n1,__FILE__,__LINE__);
    printf ("    to_is_tainted=%d\n",
	    to_is_tainted);
    if (foo && to_is_tainted
	&& (exists_taint_with_label(wctull(p1),n1, "key-startup-0-2c", __FILE__,__LINE__)))
      printf ("    to now tainted with 2c\n");
  }  
}
}


inline void info_flow_label(unsigned long long p, size_t n, char *label) {

  if (debug_at_least_med()) {
    printf ("    info_flow_label ");
    render_address(p);
    printf (" %d %s\n", (uint32_t) n, label);
  }

  if (debug_at_least_med()) {
    trl_boolean was_tainted;
    printf ("    info_flow_label (p=");
    render_address(p);
    printf (") (n=%d) (label=%s)\n", (uint32_t) n, label);
    was_tainted = exists_taint(wctull(p),n,__FILE__,__LINE__);
    printf ("    was_tainted=%d\n", was_tainted);
    if (foo && was_tainted
        && (exists_taint_with_label(wctull(p),n, "key-startup-0-2c", __FILE__,__LINE__)))
      printf ("    was tainted with 0-2c\n");
  }
  label_taint(wctull(p),n,label,"NONE",-1);
  if (loglog==TRUE) {
    loglog_label(p,if_key_num,n);
  }
  label_taint_count ++;
  if (debug_at_least_med()) {
    trl_boolean t = exists_taint(wctull(p),n,__FILE__,__LINE__);
    assert (t==TRUE);
  }
}


///////////////////////////////////////////////////////////


/* 
   p1 is presumed to be the address of some info-flow 
   register (fake address).
   load of bytes (p2,p2+n-1) from memory into bottom n bytes of 
   fake register. 
   if u is True then this is an unsigned load, so if
   n<4 we zero out higher-order bytes of the register at p1.  
   otherwise we sign-extend
*/
inline void info_flow_ld(unsigned long long p1, unsigned long long p2, size_t n, trl_boolean u) {

  // NB: you are IGNORING u which is wrong!  
  //  if (if_debug == TRUE) 
  //    printf ("info_flow_ld %p %p %d %d\n", p1, p2, n, u);
  // um, we shouldn't have 64-bit lds yet...
  assert (n<=4);
  // copy the lower n bytes from p2 into reg at p1
  info_flow_copy(p1,p2,n);
  // delete info for upper bytes.
  if (n<4) {
    info_flow_delete(p1+n,4-n);
  }
}


// p1 is address of some info-flow register (fake address).
// store the low n bytes of that register at location p2.  
inline void info_flow_st(unsigned long long p1, unsigned long long p2, size_t n) {
  //  if (if_debug == TRUE) 
  //    printf ("info_flow_st %p %p %d\n", p1, p2, n);
  info_flow_ld(p2,p1,n,TRUE);
}


/////////////////////////////////////////


// delete info-flow for n bytes of register number rn, starting at offset o.
// if we delete for all 4 byts, then we can set the big falg.
inline void if_delete_reg_aux (uint32_t rn, uint32_t o, uint32_t n) {
  //  assert (rn != UNINITIALIZED);			
  if (debug_at_least_med()) {
    check_reg_taint(rn,__FILE__,__LINE__);
    printf ("  if_delete_reg_aux r=%s o=%d n=%d\n",
	    info_flow_reg_str[rn], o, n);
  }
  // only bother if reg *may* be tainted 
  if (info_flow_possibly_tainted(rn)) {		
    if (debug_at_least_med()) 
      printf ("%s possibly tainted\n", info_flow_reg_str[rn]);
    // untaint 
    info_flow_delete(IFRBA(rn)+o,n);		 
    if (o==0 && n==4) {
      // if we untainted the whole thing.  take note. 
      info_flow_mark_as_not_possibly_tainted(rn); 
    }
  }   
  else {
    if (debug_at_least_med()) {
      printf ("%s NOT possibly tainted\n", info_flow_reg_str[rn]);
    }
  }
  if (debug_at_least_med()) {
    check_reg_taint(rn,__FILE__,__LINE__);
  }
}


// most common case.  delete info-flow for all of 4-byte register.
inline void if_delete_r4(uint32_t rn) {
  if_delete_reg_aux(rn,0,4);
}


// just delete bottom 2 bytes 
inline void if_delete_r2(uint32_t rn) {
  if_delete_reg_aux(rn,0,2);
}


// just delete bottom byte
inline void if_delete_r1(uint32_t rn) {
  if_delete_reg_aux(rn,0,1);
}


/*
  Update info-flow graph to represent that 
  n bytes of register number rn1 starting from offset o1,
  is a copy of the n bytes of register number rn2 starting from offset o2.
  note: if rn2 is NOT tainted, we just untaint the 
  n bytes of rn1 starting with offset o1
*/
// rn1 is dest
// rn2 is source
inline void if_copy_regs_aux (uint32_t rn1, uint32_t o1, uint32_t rn2, uint32_t o2, uint32_t n) {
  //  assert (rn1 != UNINITIALIZED && rn2 != UNINITIALIZED);	
  if (debug_at_least_med()) {
    check_reg_taint(rn1,__FILE__,__LINE__);
    check_reg_taint(rn2,__FILE__,__LINE__);
    printf ("  if_copy_regs_aux (r1=%s o1=%d) (r2=%s o2=%d) n=%d\n",
	    info_flow_reg_str[rn1], o1, 
	    info_flow_reg_str[rn2], o2, n);
  }
  if (info_flow_possibly_tainted(rn2)) {  
    if (debug_at_least_med()) {
      printf ("%s possibly tainted\n", info_flow_reg_str[rn2]);
    }
    info_flow_copy(IFRBA(rn1)+o1,IFRBA(rn2)+o2,n);   
    info_flow_mark_as_possibly_tainted(rn1); 
  } 
  else { 
    if (debug_at_least_med()) {
      printf ("%s NOT possibly tainted\n", info_flow_reg_str[rn2]);
    }
    if (o1==0 && o2==0 && n==4 && info_flow_possibly_tainted(rn1)) { 
      // untainted rn1 copied to possibly tainted rn2.  
      // Thus, rn2 not possibly tainted  
      info_flow_delete(IFRBA(rn1)+o1,n);	
      info_flow_mark_as_not_possibly_tainted(rn1);	    
    } 
  }   
  if (debug_at_least_med()) {
    check_reg_taint(rn1,__FILE__,__LINE__);
    check_reg_taint(rn2,__FILE__,__LINE__);
  }
}


// most common case.  copy 4-byte reg to another 4-byte reg.
inline void if_copy_r4(uint32_t rn1, uint32_t rn2) {
  if_copy_regs_aux(rn1,0,rn2,0,4);
}


// copy 2-byte reg to another 2-byte.  leave higher-order bytes alone
// NB: x86 is little-endian.
// So, the 1st byte is least significant, 2nd is next-least significant. 
inline void if_copy_r2(uint32_t rn1, uint32_t rn2) {
  if_copy_regs_aux(rn1,0,rn2,0,2);
}


// copy 1-byte reg to another 1-byte. leave higher-order bytes alone
inline void if_copy_r1(uint32_t rn1, uint32_t rn2) {
  if_copy_regs_aux(rn1,0,rn2,0,1);
}


/*
  Update info-flow graph to represent that
  n1 bytes of rn1 starting from offset o1 are
  computed from n2 bytes of rn2 starting from 
  offset o2.
  NOTE: a "non-oblitting compute transfer"
*/
// rn1 is dest
// rn2 is src
inline void if_compute_regs_aux (uint32_t rn1, uint32_t o1, uint32_t n1, 
				 uint32_t rn2, uint32_t o2, uint32_t n2) {
  //  assert (rn1 != UNINITIALIZED && rn2 != UNINITIALIZED);	
  if (debug_at_least_med()) {
    check_reg_taint(rn1,__FILE__,__LINE__);
    check_reg_taint(rn2,__FILE__,__LINE__);
  }
  if (debug_at_least_med()) {
    printf ("  if_compute_regs_aux (r1=%s o1=%d n1=%d) (r2=%s o2=%d n2=%d)\n",
	    info_flow_reg_str[rn1], o1, n1,
	    info_flow_reg_str[rn2], o2, n2);
  }
  if (info_flow_possibly_tainted(rn2)) { 
    if (debug_at_least_med()) {
      printf ("%s possibly tainted\n", info_flow_reg_str[rn2]);
    }
    //  printf("IF_COMPUTE_REGS_AUX(%d,%d,%d,%d,%d,%d)\n", rn1,o1,n1,rn2,o2,n2); 
    info_flow_compute(IFRBA(rn1)+o1,n1,IFRBA(rn2)+o2,n2); 
    info_flow_mark_as_possibly_tainted(rn1); 
  } 
  else { 
    if (debug_at_least_med()) {
      printf ("%s NOT possibly tainted\n", info_flow_reg_str[rn2]);
    }
    /*
      // TRL 0805 whoops this is just bogus, right? 
      // This is a "non-oblitting" compute transfer.  
      // if rn2 isn't possibly tainted, it should have no effect upon rn1.
    if (info_flow_possibly_tainted(rn1)) { 
      info_flow_delete(IFRBA(rn1)+o1,n1);	
      info_flow_mark_as_not_possibly_tainted(rn1); 
    } 
    */
  }
  if (debug_at_least_med()) {
    check_reg_taint(rn1,__FILE__,__LINE__);
    check_reg_taint(rn2,__FILE__,__LINE__);
  }
}


inline void if_compute_r4(uint32_t rn1, uint32_t rn2) {
  if_compute_regs_aux(rn1,0,4,rn2,0,4);
}


inline void if_compute_r2(uint32_t rn1, uint32_t rn2) {
  if_compute_regs_aux(rn1,0,2,rn2,0,2);
}


inline void if_compute_r1(uint32_t rn1, uint32_t rn2) {
  if_compute_regs_aux(rn1,0,1,rn2,0,1);
}


/*
  This is for all of r1 += r2, r1 -= r2, etc.
  That is, r1 computed from itself and another register.
  We do this with a temporary as it streamlines the operations
  on the taint graph.
  n is to make the self-compute based on fewer than 4 bytes.  
*/
inline void if_self_compute_regs_aux(uint32_t rn1, uint32_t rn2, uint32_t n) {
  trl_boolean r1pt, r2pt;

  //  assert (rn1 != UNINITIALIZED && rn2 != UNINITIALIZED);		
  if (debug_at_least_med()) {
    printf ("  if_self_compute_regs_aux r1=%s r2=%s n=%d\n",
	    info_flow_reg_str[rn1], info_flow_reg_str[rn2],n);
  }  
  r1pt = info_flow_possibly_tainted(rn1);
  r2pt = info_flow_possibly_tainted(rn2);  
  if (debug_at_least_med()) {
    if (r1pt == TRUE) 
      printf ("%s possibly tainted\n", info_flow_reg_str[rn1]);
    else
      printf ("%s NOT possibly tainted\n", info_flow_reg_str[rn1]);
    if (r2pt == TRUE) 
      printf ("%s possibly tainted\n", info_flow_reg_str[rn2]);
    else
      printf ("%s NOT possibly tainted\n", info_flow_reg_str[rn2]);
  }  
  if (r1pt || r2pt) {
    // we split up r1 += r2 into two parts
    // part 1: q0 = r1 + r2
    if_delete_reg_aux(IFRN_Q0,0,n); 
    if_compute_regs_aux(IFRN_Q0,0,n,rn1,0,n); 
    if_compute_regs_aux(IFRN_Q0,0,n,rn2,0,n); 
    // part 2: r1 = q0
    if_copy_regs_aux(rn1,0,IFRN_Q0,0,n); 
  } 
}


// common case -- r1+=r2 for all four bytes
inline void if_self_compute_r4(uint32_t rn1, uint32_t rn2) {
  if_self_compute_regs_aux(rn1,rn2,4);
}


// for bottom 2 bytes
inline void if_self_compute_r2(uint32_t rn1, uint32_t rn2) {
  if_self_compute_regs_aux(rn1,rn2,2);
}


// for bottom byte only
inline void if_self_compute_r1(uint32_t rn1, uint32_t rn2) {
  if_self_compute_regs_aux(rn1,rn2,1);
}


/*
  This is for r++, r-- etc.  
  Again, we make use of the temporary Q0.
  i.e. Q0 = R + 1;  R = Q0;
*/
inline void if_inc_r4(uint32_t rn) {
  if (debug_at_least_med()) {
    printf ("  if_inc_r4 r=%s\n",info_flow_reg_str[rn]);
  }
  if (info_flow_possibly_tainted(rn)) {		
    if (debug_at_least_med()) 
      printf ("%s possibly tainted\n", info_flow_reg_str[rn]);
    if_delete_r4(IFRN_Q0); 
    if_compute_r4(IFRN_Q0,rn); 
    if_copy_r4(rn,IFRN_Q0); 
  }
  else {
    if (debug_at_least_med())     
      printf ("%s NOT possibly tainted\n", info_flow_reg_str[rn]);
  }
}


/*
  load n bytes into register r from location p.
  u is a trl_boolean: True means it's an unsigned ld, False requires sign-extension
  note, location, p, is really if_addr, which we've already extracted from log.
  msn is memory suffix number.  To my peril, currently ignoring it... 
  raincheck?
  0 _raw
  1 _kernel
  2 _user
*/
inline void if_ld(uint32_t msn, uint32_t rn, uint32_t n, uint32_t u, unsigned long long p) { 
  //  assert (msn != UNINITIALIZED); 
  //  assert (rn != UNINITIALIZED); 
  //  assert (p != (char *) UNINITIALIZED);	
  if (debug_at_least_med()) {
    check_reg_taint(rn,__FILE__,__LINE__);
  }
  if (debug_at_least_med()) {
    printf ("if_ld msn=%d rn=%d n=%d u=%d p=%p\n", msn,rn,n,u,p);
  }
  info_flow_ld( IFRBA(rn), p, n, u);	
  // assume rn might now be tainted.  
  info_flow_mark_as_possibly_tainted(rn);
  if (debug_at_least_med()) {
    check_reg_taint(rn,__FILE__,__LINE__);
  }
}


inline void if_ldu(uint32_t msn, uint32_t rn, uint32_t n, unsigned long long p) {
  if_ld(msn,rn,n,TRUE,p);
}


inline void if_lds(uint32_t msn, uint32_t rn, uint32_t n, unsigned long long p) {
  if_ld(msn,rn,n,FALSE,p);
}


// store low n bytes of register r at location p. 
// msn is memory suffix number. 
inline void if_st(uint32_t msn, uint32_t rn, uint32_t n, unsigned long long p) {
  if (debug_at_least_med()) {
    check_reg_taint(rn,__FILE__,__LINE__);
  }
  if (info_flow_possibly_tainted(rn)) {		
    if (debug_at_least_med()) {
      printf ("if_st msn=%d r=%s n=%d p=%p\n", msn,info_flow_reg_str[rn],n,p);
      printf ("%s possibly tainted\n", info_flow_reg_str[rn]);
    }
    // note: no way to *mark* an address as possibly tainted.  
    info_flow_st(IFRBA(rn), p, n);	
  } 
  else {
    if (debug_at_least_med()) 
      printf ("%s NOT possibly tainted\n", info_flow_reg_str[rn]);
  }
  if (debug_at_least_med()) {
    check_reg_taint(rn,__FILE__,__LINE__);
  }
}


trl_boolean addr_is_reg(unsigned long long p) {
  return  (p >= IFRBA(IFRN_EAX) && p <= IFRBA(IFRN_Q4)+3);
}


// print out everything that is tainted along with its label?
void spit_taint() {
  int i,j,nt;
  uint64_t lp;  

  printf ("\n\n===========================\n");
  printf ("spit_taint\n");
  nt=0;
  // register taintedness
  printf ("\nRegister taint:\n");
  for (j=0; j<if_key_label_ind; j++) {
    printf ("%s:\n", if_key_label[j]);
    nt = 0;
    for (i=0; i<8; i++) {
      lp = ctull(IFRBA(i)); 
      printf("lp = %ld\r\n",lp);           
      if ((exists_taint_with_label(lp,4,if_key_label[j],__FILE__,__LINE__)) == TRUE) {
	printf ("  ");
	render_address(IFRBA(i));
	printf (" T\n");
	//	trace_taint(lp,4,"foo","bar",__FILE__,__LINE__);
	nt++;
      }
    }
    printf ("\n%d tainted bytes\n\n",nt);
  }
  printf("\nMemory taint\n");
  for (j=0; j<if_key_label_ind; j++) {
    nt = 0;  
    printf ("%s:\n", if_key_label[j]);
    print_bytes_with_this_label(if_key_label[j]);
  }
  printf ("\n%d tainted bytes\n\n",nt);
  printf ("===========================\n\n");
}


// save current if log to a file for some reason    
void if_log_to_file() {
  char filename[1024];
  gzFile out;
  //  FILE *fp;

  snprintf (filename, 1024, "/scratch/tmp/ifl-%d-%d", getpid(), if_log_rollup_count);
  //  fp = fopen (filename, "w");
  out = gzopen(filename,"wb");

  //  fwrite(if_log_base, 1, if_log_ptr-if_log_base, fp);
  gzwrite(out, (char *) if_log_base, (unsigned int) (if_log_ptr - if_log_base)); 
  //  fclose(fp);
  gzclose(out);

  printf ("wrote if log to %s\n", filename);
  if_log_rollup_count ++;
}


void spit_log(char *if_p) {
  int i;
  uint8_t c;
  printf ("if_p[-127..128]: \n");
  for (i=-128; i<128; i++) {
    c = *(((uint8_t *) if_p) + i); 
    printf ("%d 0x%llx  %2x \n", i, ((uint8_t *) if_p) + i, c);
  }
  printf ("\n");
}


#ifdef USE_SENTINEL
char *check_for_sentinel(char *if_p) {
  uint32_t sentinel;

  IFLR_UNSIGNED_INT(sentinel);
  if (debug_at_least_high()) 
    printf ("if_p=%p sentinel=%x\n", if_p, sentinel);
  if (sentinel != THE_SENTINEL) {
    printf ("Sentinel = %x\n", sentinel);
    printf ("Sentinel is not 0x42424242?\n");
    printf ("if_log_base=%p\n", if_log_base);
    printf ("if_p=%p\n", if_p);
    spit_log(if_p);
  }
  assert (sentinel == THE_SENTINEL);
  if (debug_at_least_high()) 
    printf ("... found sentinel\n");
  return (if_p);
}
#endif

//this needs to be global for the 2 part HD_TRANSFER
unsigned long long if_from_val = UNINITIALIZED;

if_op_t prev_op1=1;
if_op_t prev_op2=2;
  
unsigned int ldst_work_count = 0;
unsigned int ldst_dont_work_count = 0;
  
trl_boolean if_save_env_called = FALSE;
trl_boolean if_save_env_called_previous = FALSE;

// returns the # of if_log_entry items consumed
inline char *if_process_op(char *if_p) {

  if_op_t if_op; 
  if_arg_t if_arg = UNINITIALIZED;
  if_addr_t if_addr = UNINITIALIZED;
  if_regnum_t if_regnum = UNINITIALIZED;
  if_memsuffixnum_t if_memsuffixnum = UNINITIALIZED;
  if_shift_t if_shift = UNINITIALIZED;
  if_mem_write_t if_mem_write = UNINITIALIZED;
  int if_key_val = UNINITIALIZED;
  unsigned char if_byte_val = UNINITIALIZED;
  unsigned short if_word_val = UNINITIALIZED;
  unsigned int if_long_val = UNINITIALIZED;
  unsigned long long if_to_val = UNINITIALIZED;
  size_t if_size_val = UNINITIALIZED;
  unsigned int the_eip = UNINITIALIZED;
  if_save_env_called_previous = if_save_env_called;
  if_save_env_called = FALSE;
  
  trl_boolean if_debug_was_off = TRUE;

  if (debug_at_least_high()) 
    printf ("if_p_orig = %p\n", if_p);

  if_p_orig = if_p;

#ifdef USE_SENTINEL
  if_p = check_for_sentinel(if_p);
#endif // USE_SENTINEL

  // extract the info-flow operation (one byte)
  IFLR_OP(if_op);

  if_current_op = if_op;

  if (if_op == INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T0_A0) {
    //    printf("foo\n");
  }

  // sanity check
  if (if_op >= DUMMY_LAST_OP) {
    printf ("if_op = %d\n", if_op);
  }
  assert (if_op <= DUMMY_LAST_OP);

  prev_op2 = prev_op1;
  prev_op1 = if_op;

  if (if_count_ops == TRUE) {
    if_op_hist[if_op] ++;
  }

  if (debug_at_least_med()) 
    printf ("if_op=0x%x [%s]\n", if_op, if_op_str(if_op));

  // if necessary, get argument (one byte)
  if ((info_flow_takes_an_arg(if_op)) == TRUE) {
    IFLR_UNSIGNED_INT(if_arg);
    if (debug_at_least_med()) 
      printf ("if_op takes an arg: %d\n", if_arg);
    // convert argument into its various required forms
    if ((info_flow_takes_regnum(if_op)) == TRUE) {
      if (debug_at_least_high()) 
	printf ("... arg is a regnum\n");
      if_regnum = (if_regnum_t) if_arg;
    }
    else {
      if ((info_flow_takes_memsuffixnum(if_op)) == TRUE) {
	if (debug_at_least_high()) 
	  printf ("... arg is a memsuffixnum\n");	
	if_memsuffixnum = if_arg;
	// NB: we aren't actually doing anything with this yet!
	// raincheck?
      }
      else {
	if ((info_flow_takes_shift_only(if_op)) == TRUE) {
	  if (debug_at_least_high()) 
	    printf ("... arg is a shift only\n");
	  if_shift = if_arg;
	}
	else {
	  if ((info_flow_takes_shift_and_mem_write(if_op)) == TRUE) {
	    // and with 0000 1100 and shift right two bits
	    if_shift = (if_arg & 0xc) >> 2;
	    // and with 0000 0011
	    if_mem_write = if_arg & 0x3;	
	    if (debug_at_least_high()) 
	      printf (".. arg is shift/mem_write: %d %d\n", if_shift,if_mem_write);
	    // NB: also not doing anything with this yet.  
	  }
	}
      }
    }
  }
  
  // simple case in which we've pushed an address (presumably not in the virtual memory)
  // to the info -flow log.
  if ((info_flow_takes_an_addr(if_op)) == TRUE) {
    IFLR_PTR(if_addr);
    if (debug_at_least_high()) 
      printf ("if_op takes an addr: %p\n", if_addr);    
  }

  if ((info_flow_from_ops_mem_dot_h(if_op)) == TRUE) {
    unsigned int the_eip;
    IFLR_UNSIGNED_INT(the_eip);

  if(debug_at_least_low()) 
    printf ("eip is 0x%08x\n", the_eip);
  }



  // more complicated case in which
  // We've got some kind of ld/st from ops_mem.h (or via CMPXCHG8).  
  // But that was in terms of virtual address.  We expect to see a companion 
  // log entry next from cpu-all.h, which will give us the physical address.
  // OR from softmmu_header.h it seems.  
/*  if ((if_op == INFO_FLOW_OP_CMPXCHG8B_PART1) || (if_op == INFO_FLOW_OP_CMPXCHG_T0_T1_EAX_CC_CASE2)  
      || (info_flow_from_ops_mem_dot_h(if_op)) == TRUE || if_op == INFO_FLOW_OP_SAVE_REG) {
    if_op_t if_op_temp;
    if (debug_at_least_high()) 
      printf ("non-simple takes-an-addr sitch.\n");
#ifdef USE_SENTINEL
    if_p = check_for_sentinel(if_p);
#endif // USE_SENTINEL
    IFLR_OP(if_op_temp);
    if (1==1) { //TODO: put a real condition here
      // good.  there was cpu-all.h ld/st.  address should come next. 
//      if(if_op_temp == INFO_FLOW_OP_PHYS_MEM_SOFTMMU_HEADER_ST1)
//	printf("I found the nasty bugger... ST1\r\n");
	  if(debug_at_least_low()) 
       		 printf ("if_op=0x%x [%s]\n", if_op_temp, if_op_str(if_op_temp));
      IFLR_PTR(if_addr);
    if(if_addr != 0xffffffffffffffff && if_addr != 0xfffffffffffffffe)
     { 
        IFLR_UNSIGNED_CHAR(if_byte_val);
  	if(debug_at_least_low()) 
		printf("byte value = %c\r\n",if_byte_val);
     }
     else{
       if_op_t if_op_temp2;
       if_addr_t  if_addr_temp2;
       size_t if_size_temp2;

 	 if(debug_at_least_low()) 
		printf("NICE, we got a mmapped io\r\n");
        //assert(1==0);
       if(if_addr == 0xffffffffffffffff){ //st/iowrite case
           if(IFLR_PEEK_OP() == INFO_FLOW_OP_HD_TRANSFER_PART2){
  	if(debug_at_least_low()) 
             printf("We're handling an io_write to the HD\r\n");
	#ifdef USE_SENTINEL
	  if_p = check_for_sentinel(if_p);
	#endif // USE_SENTINEL
             IFLR_OP(if_op_temp2);
             IFLR_PTR(if_addr_temp2);
             IFLR_SIZE(if_size_temp2);
             if_addr  = if_addr_temp2;
           }
           else{
  	if(debug_at_least_low()) 
              printf("Dropping a ST address, we should stop here!\r\n");
           }
	}	
       else if(if_addr == 0xfffffffffffffffe){ //ld/ioread case
           if(IFLR_PEEK_OP() == INFO_FLOW_OP_HD_TRANSFER_PART1){
  	if(debug_at_least_low()) 
             printf("We're handling an io_read from the HD\r\n");
		#ifdef USE_SENTINEL
		  if_p = check_for_sentinel(if_p);
		#endif // USE_SENTINEL
	     IFLR_OP(if_op_temp2);
             IFLR_PTR(if_addr_temp2);
             if_addr  = if_addr_temp2;
           }
           else{
  	if(debug_at_least_low()) 
              printf("Dropping a LD address, we should stop here!\r\n");
           }
	}
	else{
 		printf("WTF MATE, LDST ERROR\r\n");
 		printf("WTF MATE, LDST ERROR\r\n");
 		printf("WTF MATE, LDST ERROR\r\n");
 		printf("WTF MATE, LDST ERROR\r\n");
        	assert(1 == 0);
        }	
     }
	if(if_byte_val == 'Z'){
  	if(debug_at_least_low()) 
		printf("We're seeing Z at 0x%08x\r\n",if_addr);
		 if(exists_taint(if_addr,1,__FILE__,__LINE__)){
  		if(debug_at_least_low()) 
                        printf("we be tainted\r\n");
                }
		else{
  			if(debug_at_least_low()) 
			printf("we not be tainted\r\n");
		}	
	}
	if(if_addr >= 0x1f4ee000  && if_addr <= (0x1f4ee000  + 4096))
	{
  		if(debug_at_least_low()) {
	  	 printf("Howdy Ho we wrote to an hd_transfer block\r\n");
		printf("Value is %c\r\n",if_byte_val);
		}
		if(exists_taint(if_addr,1,__FILE__,__LINE__)){
			printf("WOO HOO, we should be seeing taint\r\n");
		}
        }
	
	}
     // IFLR_UNSIGNED_CHAR(if_byte_val);
    //  printf("pulling val:%02x off the log\r\n",if_byte_val);


         
      if (debug_at_least_high()) {
	printf ("saw ops_mem info-flow followed by cpu-all phsyical ld/st\n");
      }
    }
    else {
      printf ("I just saw an info flow from ops_mem.h (or cmpxch8b).\n");
      printf ("I expected to see some physical ld/st from cpu-all.h "
	      "or softmmu_header.h to come next.\n");
      printf ("I didn't\n");
      printf ("if_op = %d %s\n", if_op_temp, if_op_str(if_op_temp));
      spit_log(if_p);
      assert (1==0);
    }
  }

  
  // There are tons of loads and stores in target-i386 that aren't precipitated
  // by a translated x86 instr.  
  // translate.c: uses phys mem ld functions to fetch code, i.e. 
  //    instructions and parameters
  // helper.c: manage hairy tss etc
  //    we need to just drop these on the floor for now. 
  else {
    if (1==1){ //TODO: put a real condition here
      // discard the address
      IFLR_PTR(if_addr);
      if(if_addr != 0xffffffffffffffff && if_addr != 0xfffffffffffffffe){
         IFLR_UNSIGNED_CHAR(if_byte_val);
  	if(debug_at_least_low()){
      printf("pulling val:%02x off the log\r\n",if_byte_val);
       	printf("Dropping ld/st addr 0x%08x on the floor!\r\n",if_addr);
	}
	 if(if_byte_val == 'Z'){
  		if(debug_at_least_low())
                printf("We're seeing Z at 0x%08x\r\n",if_addr);
                 if(exists_taint(if_addr,1,__FILE__,__LINE__)){
  			if(debug_at_least_low())
                        printf("we be tainted\r\n");
                }
                else{
  			if(debug_at_least_low())
                        printf("we not be tainted\r\n");
                }
        }

      }
      return (if_p); 
    }
  }
*/
  //RWS 0905 this is our new and improved memory stiching
  //This method compares the virtual address of the load/store instruction
  //to the virtual address in the virtual to real operation
  if(info_flow_from_ops_mem_dot_h(if_op)){ //punting on op_template_mem.h for now 
	if_addr_t temp_ldst_virt_addr = UNINITIALIZED;
	if_op_t if_temp_op = UNINITIALIZED;
	if_addr_t temp_softmmu_virt_addr = UNINITIALIZED;
	if_addr_t temp_softmmu_real_addr = UNINITIALIZED;
	unsigned char temp_byte_val = UNINITIALIZED;
	unsigned char temp_access_type = UNINITIALIZED;
	char* tainted = "FALSE";
	
	//pulll the virtual address off the log
	IFLR_PTR(temp_ldst_virt_addr);
	if(debug_at_least_low())
	printf("LDST:%s memsuffixnum:%d looking for virt addr = 0x%08x\r\n",if_op_str(if_op),if_arg,temp_ldst_virt_addr);
  	//look for an address to stich
  	do{
            #ifdef USE_SENTINEL
	    	if_p = check_for_sentinel(if_p);
	    #endif // USE_SENTINEL
	    IFLR_OP(if_temp_op);
	    if(info_flow_op_from_softmmu(if_temp_op)){
		IFLR_PTR(temp_softmmu_virt_addr);	
		IFLR_PTR(temp_softmmu_real_addr);	
 		if(info_flow_op_from_softmmu_and_has_byte_arg(if_temp_op)){
               		IFLR_UNSIGNED_CHAR(temp_byte_val);
	        }
		IFLR_UNSIGNED_CHAR(temp_access_type);
		if(info_flow_is_store_op(if_op)){
			if(exists_taint(IFRBA(IFRN_T0),4,__FILE__,__LINE__) || exists_taint(IFRBA(IFRN_T1),4,__FILE__,__LINE__))
			tainted = "TRUE";
		}
		if(info_flow_is_load_op(if_op)){
			if(exists_taint(temp_softmmu_real_addr,4,__FILE__,__LINE__))
			tainted = "TRUE";
		} 
	if(debug_at_least_low())
		printf("SOFTMMU addr op=%s virt_addr=0x%08x real_addr=0x%08x access_type=%d val=%c tainted=%s\r\n",if_op_str(if_temp_op),temp_softmmu_virt_addr,temp_softmmu_real_addr,(int)temp_access_type,temp_byte_val,tainted);
	    }//else we should fail, we've hit a non-memory instruction
	    else if(if_temp_op == INFO_FLOW_OP_TLB_FILL){
		if(debug_at_least_low())
		printf("We just hit a TLB fill!\r\n");
	    }
	    else if(if_temp_op == INFO_FLOW_OP_SAVE_ENV){
		if(debug_at_least_low())
		printf("SAVE_ENV called\r\n");
	    	if(IFLR_PEEK_OP()!=INFO_FLOW_OP_RESTORE_ENV)
			if(debug_at_least_low())
			printf("YO!, we found a gap\r\n");	
	    }
	    else if(if_temp_op == INFO_FLOW_OP_RESTORE_ENV){
		if(debug_at_least_low())
		printf("RESTORE_ENV called\r\n");
	    }
	    else{
		if(debug_at_least_low())
		printf("We've gone through all the memory instructions and hit  anon memory instruction:%s\r\n",if_op_str(if_temp_op));
	//	exit(-1);
		//put if_p back to before op
		if_p -= sizeof(uint32_t);
		#ifdef USE_SENTINEL
		if_p -= sizeof(uint32_t);
		#endif
		ldst_dont_work_count++;
		break;	
	    }
	} while(temp_ldst_virt_addr != temp_softmmu_virt_addr);
	//great, we've found the addr
	ldst_work_count++;
	if_addr = temp_softmmu_real_addr;
	if(debug_at_least_low())
	printf("FOUND ADDR virt_addr=0x%08x real_addr=0x%08x val=%c\r\n",temp_softmmu_virt_addr,temp_softmmu_real_addr,temp_byte_val);
  } //drop all the extra address that we don't need
  else if(info_flow_op_from_softmmu(if_op)){
	if_addr_t temp_virt_addr;
	if_addr_t temp_real_addr;
	unsigned char temp_byte_val = UNINITIALIZED;
	unsigned char temp_access_type = UNINITIALIZED;
   
        IFLR_PTR(temp_virt_addr);
	IFLR_PTR(temp_real_addr);
	if(info_flow_op_from_softmmu_and_has_byte_arg(if_op)){
		IFLR_UNSIGNED_CHAR(temp_byte_val);
	}	
	IFLR_UNSIGNED_CHAR(temp_access_type);

	if(info_flow_op_is_mmu_store_addr(if_op)){
              if(exists_taint(IFRBA(IFRN_T0),4,__FILE__,__LINE__) || exists_taint(IFRBA(IFRN_T1),4,__FILE__,__LINE__))
        	printf("WHOA, we're throwing away good cheese!\r\n");        
	}	
	if(debug_at_least_low())
	printf("Dropping op %s with virtual addr=0x%08x real addr=0x%08x access_type=%d val=%c\r\n",if_op_str(if_op),temp_virt_addr, temp_real_addr, temp_access_type, temp_byte_val);
  }
  
  // keyboard input.  takes one param -- the keycode.
  if (if_op == INFO_FLOW_OP_KEYBOARD_INPUT) {
    uint32_t temp;
    if (debug_at_least_med()) {
      printf ("op was INFO_FLOW_OP_KEYBOARD_INPUT. Pulling val off log.\n");
      spit_taint();
    }
    IFLR_UNSIGNED_INT(temp);
    if_key_val = (int) temp;
  }

  // another special case.  time to change the keyboard label. 
  if (if_op == INFO_FLOW_OP_NEW_KEYBOARD_LABEL) {
    uint32_t i,l;
    if (debug_at_least_med()) {
      printf ("op was INFO_FLOW_NEW_KEYBOARD_LABEL.  "
	      "Obtaining new label string from log.\n");
    }
    // pull length of label (string) out of info-flow-log
    IFLR_UNSIGNED_INT(l);
    // and then pull out all the chars as well
    for (i=0; i<l; i++) {
      IFLR_UNSIGNED_CHAR(if_keyboard_label[i]);
    }
    if_keyboard_label[l] = '\0';
    printf ("new keyboard label is %s\n", if_keyboard_label);
  }
  
  // another special case.  time to change the network label. 
  if (if_op == INFO_FLOW_OP_NEW_NETWORK_LABEL) {
    uint32_t i,l;
    if (debug_at_least_med()) {
      printf ("op was INFO_FLOW_NEW_NETWORK_LABEL.  "
	      "Obtaining new label string from log.\n");
    }
    // pull length of label (string) out of info-flow-log
    IFLR_UNSIGNED_INT(l);
    // and then pull out all the chars as well
    for (i=0; i<l; i++) {
      IFLR_UNSIGNED_CHAR(if_network_label[i]);
    }
    if_network_label[l] = '\0';
    printf ("new network label is %s\n", if_network_label);
  }
 
if (if_op == INFO_FLOW_OP_NETWORK_INPUT_BYTE_T0){
    unsigned int temp;
    IFLR_UNSIGNED_INT(temp);
    if_byte_val = (unsigned char) temp;
  }

  if (if_op == INFO_FLOW_OP_NETWORK_INPUT_BYTE_T1){
    unsigned int temp;
    IFLR_UNSIGNED_INT(temp);
    if_byte_val = (unsigned char) temp;
  }

  if (if_op == INFO_FLOW_OP_NETWORK_INPUT_WORD_T0){
    unsigned int temp;
    IFLR_UNSIGNED_INT(temp);
    if_word_val = (unsigned short) temp;
  }

  if (if_op == INFO_FLOW_OP_NETWORK_INPUT_WORD_T1){
    unsigned int temp;
    IFLR_UNSIGNED_INT(temp);
    if_word_val = (unsigned short) temp;
  }

  if (if_op == INFO_FLOW_OP_NETWORK_INPUT_LONG_T0){
    IFLR_UNSIGNED_INT(if_long_val);
  }

  if (if_op == INFO_FLOW_OP_NETWORK_INPUT_LONG_T1){
    IFLR_UNSIGNED_INT(if_long_val);
  }
	
  if(if_op == INFO_FLOW_OP_HD_TRANSFER){
    IFLR_UNSIGNED_LONG_LONG(if_from_val);
    IFLR_UNSIGNED_LONG_LONG(if_to_val);
    IFLR_SIZE(if_size_val);

    if(IFLR_PEEK_OP() == INFO_FLOW_OP_CPU_READ_ADDR){
      if_op_t if_temp_op;
      unsigned long long if_temp_addr;
      #ifdef USE_SENTINEL
   	if_p = check_for_sentinel(if_p);
      #endif // USE_SENTINEL
      IFLR_OP(if_temp_op);
      IFLR_UNSIGNED_LONG_LONG(if_temp_addr);
	if(debug_at_least_low())
      printf("cpu read addr:0x%08x if_from_val:0x%08x\r\n",if_temp_addr,if_from_val);
      if_from_val = if_temp_addr;
    }
    
    if(IFLR_PEEK_OP() == INFO_FLOW_OP_CPU_WRITE_ADDR){
      if_op_t if_temp_op;
      unsigned long long if_temp_addr;
      #ifdef USE_SENTINEL
   	if_p = check_for_sentinel(if_p);
      #endif // USE_SENTINEL
      IFLR_OP(if_temp_op);
      IFLR_UNSIGNED_LONG_LONG(if_temp_addr);
	if(debug_at_least_low())
      printf("cpu write addr:0x%08x if_to_val:0x%08x\r\n",if_temp_addr,if_to_val);
      if_to_val = if_temp_addr;
    }
  }

  if(if_op == INFO_FLOW_OP_CPU_READ_ADDR || if_op == INFO_FLOW_OP_CPU_WRITE_ADDR){
	unsigned long long if_temp_addr;
	IFLR_UNSIGNED_LONG_LONG(if_temp_addr);
	if(debug_at_least_low())
	printf("OOPS, we've got a cpu_read write that we're dropping, addr:0x%08x\r\n",if_temp_addr);
  }

  if(if_op == INFO_FLOW_OP_HD_TRANSFER_PART1){
    IFLR_UNSIGNED_LONG_LONG(if_from_val);
  }
 
  if(if_op == INFO_FLOW_OP_HD_TRANSFER_PART2){
    IFLR_UNSIGNED_LONG_LONG(if_to_val);
    IFLR_SIZE(if_size_val);
  }
	
  if(if_op == INFO_FLOW_OP_X86_INSN){
	IFLR_UNSIGNED_INT(if_long_val);
  }

  if (debug_at_least_med()) {
    printf ("if_current_op_ind=%d", if_current_op_ind);
    printf ("(%ld of %ld bytes) ",
	    (if_p_orig - if_log_base), 
	    (if_log_ptr - if_log_base));
    printf ("if_op=%s\n", if_op_str(if_op));
    if (if_regnum != UNINITIALIZED){
      printf ("if_regnum = %d\r\n",if_regnum);
      printf ("r=%s \r\n", if_reg_str(if_regnum));
    }
    if (if_memsuffixnum != UNINITIALIZED)
      printf ("ms=%s ", if_memsuffix_str(if_memsuffixnum));
    if (if_shift != UNINITIALIZED)
      printf ("s=%d ", if_shift);
    if (if_mem_write != UNINITIALIZED)
      printf ("mw=%d ", if_mem_write);
    if ((long)if_addr != UNINITIALIZED)
      printf ("a=%p ", if_addr);
    if (if_key_val != UNINITIALIZED)
      printf ("kv=%x ", if_key_val);
    printf ("\n");
  }

  /*
    This huge case statement reflects the structure of op.c.
    ... plus the various files like opreg_template.h that get included
    multiple times for different ifdefs.  
  */

  switch (if_op) {

    /* 
       Start of opreg_template.h
    */

    /* 
       This stuff (through INFO_FLOW_OP_MOVH_REG_T1) all parallels
       that which is in opreg_template.h in target-i386.
       we keep REG opaque and code the register directly in the 
       info flow log element. Thus, we don't need to play same
       trick of including that file over and over.  
    */

    // A0 = (uint32_t)REG; 
  case INFO_FLOW_OP_REG_MOVL_A0_R:  
    if_copy_r4(IFRN_A0,if_regnum);
    break;

    // A0 = (uint32_t)(A0 + REG);
  case INFO_FLOW_OP_REG_ADDL_A0_R:
    // A0 = (uint32_t)(A0 + (REG << 1)); 
  case INFO_FLOW_OP_REG_ADDL_A0_R_S1:
    // A0 = (uint32_t)(A0 + (REG << 2));
  case INFO_FLOW_OP_REG_ADDL_A0_R_S2:
    // A0 = (uint32_t)(A0 + (REG << 3));
  case INFO_FLOW_OP_REG_ADDL_A0_R_S3:
    if_self_compute_r4(IFRN_A0,if_regnum);
    break;

    /*
      NB: skipping bloody 64-bit for now
      void OPPROTO glue(op_movq_A0,REGNAME)(void)
      void OPPROTO glue(op_addq_A0,REGNAME)(void)
      void OPPROTO glue(glue(op_addq_A0,REGNAME),_s1)(void)
      void OPPROTO glue(glue(op_addq_A0,REGNAME),_s2)(void)
      void OPPROTO glue(glue(op_addq_A0,REGNAME),_s3)(void)
    */

    // T0 = REG;
  case INFO_FLOW_OP_REG_MOVL_T0_R:
    if_copy_r4(IFRN_T0,if_regnum);
    break;
    
    // T1 = REG;
  case INFO_FLOW_OP_REG_MOVL_T1_R:
    if_copy_r4(IFRN_T1,if_regnum);
    break;

    // T0 = REG >> 8;
  case INFO_FLOW_OP_REG_MOVH_T0_R:
    if_delete_r4(IFRN_T0);
    if_compute_r4(IFRN_T0,if_regnum);
    break;

    // T1 = REG >> 8;
  case INFO_FLOW_OP_REG_MOVH_T1_R:
    if_delete_r4(IFRN_T1);
    if_compute_r4(IFRN_T1,if_regnum);
    break;

    // REG = (uint32_t)T0;
  case INFO_FLOW_OP_REG_MOVL_R_T0:
    if_copy_r4(if_regnum,IFRN_T0);
    break;
    
    // REG = (uint32_t)T1;
  case INFO_FLOW_OP_REG_MOVL_R_T1:
    if_copy_r4(if_regnum,IFRN_T1);
    break;
    
    // REG = (uint32_t)A0;
  case INFO_FLOW_OP_REG_MOVL_R_A0:
    if_copy_r4(if_regnum,IFRN_A0);
    break;

    /*
      Skipping 64-bit again 
      void OPPROTO glue(glue(op_movq,REGNAME),_T0)(void)
      void OPPROTO glue(glue(op_movq,REGNAME),_T1)(void)
      void OPPROTO glue(glue(op_movq,REGNAME),_A0)(void)
    */

    // mov T1 to REG.  (NB: we are inside the conditional.  So really this isa MOVW.)
    // REG = (REG & ~0xffff) | (T1 & 0xffff);
    // here, copy low 2 bytes from T1 to REG and leave top 24 bytes of REG alone.
  case INFO_FLOW_OP_REG_CMOVW_R_T1_T0:
    if_copy_r2(if_regnum,IFRN_T1);
    break;

    // mov T1 to REG if T0
    // REG = (uint32_t)T1;
    // here, different from previous.  
    // copy low 4 bytes from T1 to REG and zero anything in REG above those 4 bytes.  
  case INFO_FLOW_OP_REG_CMOVL_R_T1_T0:
    if_copy_r4(if_regnum,IFRN_T1);
    break; 

    /*
      Skipping 64 bit.
      void OPPROTO glue(glue(op_cmovq,REGNAME),_T1_T0)(void)
    */

    // REG = (REG & ~0xffff) | (T0 & 0xffff);
  case INFO_FLOW_OP_REG_MOVW_R_T0:
    if_copy_r2(if_regnum,IFRN_T0);
    break;
    
    // REG = (REG & ~0xffff) | (T1 & 0xffff);
  case INFO_FLOW_OP_REG_MOVW_R_T1:
    if_copy_r2(if_regnum,IFRN_T1);
    break;
    
    // REG = (REG & ~0xffff) | (A0 & 0xffff);
  case INFO_FLOW_OP_REG_MOVW_R_A0:
    if_copy_r2(if_regnum,IFRN_A0);
    break;  

    // REG = (REG & ~0xff) | (T0 & 0xff);
  case INFO_FLOW_OP_REG_MOVB_R_T0:
    if_copy_r1(if_regnum,IFRN_T0);
    break;
    
    // REG = (REG & ~0xff00) | ((T0 & 0xff) << 8);
  case INFO_FLOW_OP_REG_MOVH_R_T0:
    if_copy_regs_aux(if_regnum,1,IFRN_T0,1,1);
    break;
    
    // REG = (REG & ~0xff) | (T1 & 0xff);
  case INFO_FLOW_OP_REG_MOVB_R_T1:
    if_copy_r1(if_regnum,IFRN_T1);
    break;

    // REG = (REG & ~0xff00) | ((T1 & 0xff) << 8);
  case INFO_FLOW_OP_REG_MOVH_R_T1:
    if_copy_regs_aux(if_regnum,1,IFRN_T1,1,1);
    break;

    /*
      TRL 0802 Skipping 64-bit versions
      i.e. env->regs[9..15]
    */

    /* 
       End of opreg_template.h 
    */

    // T0 += T1;      
  case INFO_FLOW_OP_ADDL_T0_T1:
    // T0 |= T1;
  case INFO_FLOW_OP_ORL_T0_T1:
    // T0 &= T1;
  case INFO_FLOW_OP_ANDL_T0_T1:
    // T0 -= T1;
  case INFO_FLOW_OP_SUBL_T0_T1:
    // T0 ^= T1;
  case INFO_FLOW_OP_XORL_T0_T1:
    if_self_compute_r4(IFRN_T0,IFRN_T1);
    break;

    // T0 = -T0;
  case INFO_FLOW_OP_NEGL_T0:
    // T0++;
  case INFO_FLOW_OP_INCL_T0:
    // T0--;
  case INFO_FLOW_OP_DECL_T0:
    // T0 = ~T0;
  case INFO_FLOW_OP_NOTL_T0:
    // T0 = bswap32(T0);
  case INFO_FLOW_OP_BSWAPL_T0:
    // helper_bswapq_T0();
    if_inc_r4(IFRN_T0);
    break;

    /*
      TRL 0802 Not bothering with 64-bit.
      Thus, skipping op_bswapq_T0
    */

    // MULB:
    // res = (uint8_t)EAX * (uint8_t)T0;
    // EAX = (EAX & ~0xffff) | res;
    // IMULB:
    // res = (int8_t)EAX * (int8_t)T0;
    // EAX = (EAX & ~0xffff) | (res & 0xffff);
  case INFO_FLOW_OP_MULB_AL_T0:
  case INFO_FLOW_OP_IMULB_AL_T0:
    // q1(0..1) der (eax(0),t0(0))
    if_delete_r4(IFRN_Q1);
    if_compute_regs_aux(IFRN_Q1,0,2,IFRN_EAX,0,1);
    if_compute_regs_aux(IFRN_Q1,0,2,IFRN_T0,0,1);
    // eax(0..1) = q1(0..1)
    if_copy_r2(IFRN_EAX,IFRN_Q1);    
    break;

    // MULW:
    // res = (uint16_t)EAX * (uint16_t)T0;
    // EAX = (EAX & ~0xffff) | (res & 0xffff);
    // EDX = (EDX & ~0xffff) | ((res >> 16) & 0xffff);
  case INFO_FLOW_OP_MULW_AX_T0:
  case INFO_FLOW_OP_IMULW_AX_T0:
    // q1(0..3) der (eax(0..1),t0(0..1))
    if_delete_r4(IFRN_Q1);
    if_compute_regs_aux(IFRN_Q1,0,4,IFRN_EAX,0,2);
    if_compute_regs_aux(IFRN_Q1,0,4,IFRN_T0,0,2);
    // eax(0..1) = q1(0..1)
    if_copy_regs_aux(IFRN_EAX,0,IFRN_Q1,0,2);    
    // edx(0..1) = q1(2..3)
    if_copy_regs_aux(IFRN_EDX,0,IFRN_Q1,2,2);
    break;

    // MULL:
    // res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0);
    // EAX = (uint32_t)res;
    // EDX = (uint32_t)(res >> 32);
    // IMULL:
    // res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0);
    // EAX = (uint32_t)(res);
    // EDX = (uint32_t)(res >> 32);
  case INFO_FLOW_OP_MULL_EAX_T0:
  case INFO_FLOW_OP_IMULL_EAX_T0:
    // q1(0..3) der (eax(0..3),t0(0..3))
    if_delete_r4(IFRN_Q1);
    if_compute_r4(IFRN_Q1,IFRN_EAX);
    if_compute_r4(IFRN_Q1,IFRN_T0);
    // q2(0..3) der (eax(0..3),t0(0..3))
    if_delete_r4(IFRN_Q2);
    if_compute_r4(IFRN_Q2,IFRN_EAX);
    if_compute_r4(IFRN_Q2,IFRN_T0);
    // eax(0..3) = q1(0..3)
    if_copy_r4(IFRN_EAX,IFRN_Q1);
    // edx(0..3) = q2(0..3)
    if_copy_r4(IFRN_EDX,IFRN_Q2);
    break;

    // res = (int16_t)T0 * (int16_t)T1;
    // T0 = res;
  case INFO_FLOW_OP_IMULW_T0_T1:
    // q1(0..2) der (t0(0..1),t1(0..1))
    if_delete_r4(IFRN_Q1);
    if_compute_regs_aux(IFRN_Q1,0,4,IFRN_T0,0,2);
    if_compute_regs_aux(IFRN_Q1,0,4,IFRN_T1,0,2);
    // t0(0..3) = q1(0..3)
    if_copy_r4(IFRN_EAX,IFRN_Q1);    

    break;

    // res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
    // T0 = res;
  case INFO_FLOW_OP_IMULL_T0_T1:
    // okay, we're screwed here.  looks like T0 *has* to be 64-bit?
    if_delete_r4(IFRN_T0);
    break;

    /*
      TRL 0802 
      Ignoring 64-bit 
      op_mulq_EAX_T0
      op_imulq_EAX_T0
      op_imulq_T0_T1
    */

    /*
    num = (EAX & 0xffff);
    den = (T0 & 0xff);
    if (den == 0) {
        raise_exception(EXCP00_DIVZ);
    }
    q = (num / den);
    if (q > 0xff)
        raise_exception(EXCP00_DIVZ);
    q &= 0xff;
    r = (num % den) & 0xff;
    EAX = (EAX & ~0xffff) | (r << 8) | q;
    */

  case INFO_FLOW_OP_DIVB_AL_T0:
  case INFO_FLOW_OP_IDIVB_AL_T0:
    // q1(0..1) = eax(0..1)         num
    if_copy_r2(IFRN_Q1,IFRN_EAX);
    // q2(0) = t0(0)                den
    if_copy_r1(IFRN_Q2,IFRN_T0);
    // q(0) der (q1(0..1),q2(0))   q
    if_delete_r4(IFRN_Q3);
    if_compute_regs_aux(IFRN_Q3,0,1,IFRN_Q1,0,2);
    if_compute_regs_aux(IFRN_Q3,0,1,IFRN_Q2,0,1);
    // q4(0) der (q1(0..1),q2(0))   r
    if_delete_r4(IFRN_Q4);
    if_compute_regs_aux(IFRN_Q4,0,1,IFRN_Q1,0,2);
    if_compute_regs_aux(IFRN_Q4,0,1,IFRN_Q2,0,1);
    // eax(0) = q3(0)
    if_copy_r1(IFRN_EAX,IFRN_Q3);
    // eax(1) = q4(0)
    if_copy_regs_aux(IFRN_EAX,1,IFRN_Q4,0,1);
    break;

    /*
    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
    den = (T0 & 0xffff);
    if (den == 0) {
        raise_exception(EXCP00_DIVZ);
    }
    q = (num / den);
    if (q > 0xffff)
        raise_exception(EXCP00_DIVZ);
    q &= 0xffff;
    r = (num % den) & 0xffff;
    EAX = (EAX & ~0xffff) | q;
    EDX = (EDX & ~0xffff) | r;
    */
  case INFO_FLOW_OP_DIVW_AX_T0:
  case INFO_FLOW_OP_IDIVW_AX_T0:
    // q1(0..1) = eax(0..1)               num
    if_copy_r2(IFRN_Q1,IFRN_EAX);         
    // q1(2..3) = edx(0..1)               
    if_copy_regs_aux(IFRN_Q1,2,IFRN_EDX,0,2);
    // q2(0..1) = t0(0..1)                den
    if_copy_r2(IFRN_Q2,IFRN_T0);
    // q3(0..1) der (q1(0..3),q2(0..1))   q
    if_delete_r4(IFRN_Q3);
    if_compute_regs_aux(IFRN_Q3,0,2,IFRN_Q1,0,4);
    if_compute_regs_aux(IFRN_Q3,0,2,IFRN_Q2,0,2);
    // q4(0..1) der (q1(0..3),q2(0..1))   r
    if_delete_r4(IFRN_Q4);
    if_compute_regs_aux(IFRN_Q4,0,2,IFRN_Q1,0,4);
    if_compute_regs_aux(IFRN_Q4,0,2,IFRN_Q2,0,2);
    // eax(0..1) = q3(0..1)
    if_copy_r2(IFRN_EAX,IFRN_Q3);
    // edx(0..1) = q4(0..1)
    if_copy_r2(IFRN_EAX,IFRN_Q4);
    break;

    /*
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
    den = T0;
    if (den == 0) {
        raise_exception(EXCP00_DIVZ);
    }
#ifdef BUGGY_GCC_DIV64
    r = div32(&q, num, den);
#else
    q = (num / den);
    r = (num % den);
#endif
    if (q > 0xffffffff)
        raise_exception(EXCP00_DIVZ);
    EAX = (uint32_t)q;
    EDX = (uint32_t)r;

     */
  case INFO_FLOW_OP_DIVL_EAX_T0:
  case INFO_FLOW_OP_IDIVL_EAX_T0:
    // Once again, we are in some trouble.
    // num & den & T0 need to be 64-bit...
    if_delete_r4(IFRN_EAX);
    if_delete_r4(IFRN_EDX);
    break;

    /*
      TRL 0802
      Ignoring 64 bit again.
      op_divq_EAX_T0
      op_idivq_EAX_T0
    */

    // T0 = (uint32_t)PARAM1;
  case INFO_FLOW_OP_MOVL_T0_IMU:
    // T0 = (int32_t)PARAM1;
  case INFO_FLOW_OP_MOVL_T0_IM:
    if_delete_r4(IFRN_T0);
    break;

    // T0 += PARAM1;
  case INFO_FLOW_OP_ADDL_T0_IM:
    // T0 = T0 & 0xffff;
  case INFO_FLOW_OP_ANDL_T0_FFFF:
    //  T0 = T0 & PARAM1;
  case INFO_FLOW_OP_ANDL_T0_IM:
    if_inc_r4(IFRN_T0);
    break;

    // T0 = T1;
  case INFO_FLOW_OP_MOVL_T0_T1:
    if_copy_r4(IFRN_T0,IFRN_T1);
    break;

    // T1 = (uint32_t)PARAM1;    
  case INFO_FLOW_OP_MOVL_T1_IMU:
    // T1 = (int32_t)PARAM1;
  case INFO_FLOW_OP_MOVL_T1_IM:
    if_delete_r4(IFRN_T1);
    break;

    // T1 += PARAM1;
  case INFO_FLOW_OP_ADDL_T1_IM:
    if_inc_r4(IFRN_T1);
    break;

    // T1 = A0;
  case INFO_FLOW_OP_MOVL_T1_A0:
    if_copy_r4(IFRN_T1,IFRN_A0);
    break; 

    // A0 = (uint32_t)PARAM1;
  case INFO_FLOW_OP_MOVL_A0_IM:
    if_delete_r4(IFRN_A0);
    break;

    // A0 = (uint32_t)(A0 + PARAM1);
  case INFO_FLOW_OP_ADDL_A0_IM:
    if_inc_r4(IFRN_A0);
    break;

    // A0 = (uint32_t)*(target_ulong *)((char *)env + PARAM1);
    // NB: if_addr is env+PARAM1
  case INFO_FLOW_OP_ADDR_MOVL_A0_SEG:    
    // memsuffix is 0 for _raw?  A flying leap
    if_ldu(0,IFRN_A0,4,if_addr);
    break;
 
    // A0 = (uint32_t)(A0 + *(target_ulong *)((char *)env + PARAM1));
    // NB: if_addr is env+PARAM1
  case INFO_FLOW_OP_ADDR_ADDL_A0_SEG:
    // q1 = *(if_addr)
    if_ldu(0,IFRN_Q1,4,if_addr);
    // a0 += q1
    if_self_compute_r4(IFRN_A0,IFRN_Q1);
    break;

    // A0 = (uint32_t)(A0 + (EAX & 0xff));
  case INFO_FLOW_OP_ADDL_A0_AL:
    if_self_compute_r4(IFRN_A0,IFRN_EAX);
    break;

    // A0 = A0 & 0xffff;
  case INFO_FLOW_OP_ANDL_A0_FFFF:
    if_delete_reg_aux(IFRN_A0,2,2);
    break;

    /*
      TRL0802 skipping 64-bit
      op_movq_T0_im64
      op_movq_T1_im64
      op_movq_A0_im
      op_movq_A0_im64
      op_addq_A0_im
      op_addq_A0_im64
      op_movq_A0_seg
      op_addq_A0_seg
      op_addq_A0_AL
    */

    /*
      Start handling includes of ops_mem.h in op.c.

      The following, up to INFO_FLOW_OP_STL_MEMSUFFIX_T1,
      are analogous to ops_mem.h.  That file is included
      several times by op.c with different settings for MEMSUFFIX.
      Here, MEMSUFFIX is if_mem, which we squirreled away in the log
      entry and extracted above.  
    */
    
    // T0 = *A0, just one byte. A0 is next element in log.
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T0_A0:
    if_ldu(if_memsuffixnum,IFRN_T0,1,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),1,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T0),1,IFRBA(IFRN_A0),1,0,0,"NONE","NONE",-1);
    break;
    
    // ditto, but signed.
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T0_A0:
    if_lds(if_memsuffixnum,IFRN_T0,1,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),1,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T0),1,IFRBA(IFRN_A0),1,0,0,"NONE","NONE",-1);
    break; 
      
    // T0 = *A0, 2 bytes
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T0_A0:
    if_ldu(if_memsuffixnum,IFRN_T0,2,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),2,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T0),2,IFRBA(IFRN_A0),2,0,0,"NONE","NONE",-1);
    break;

    // ditto, but signed.
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T0_A0:
    if_lds(if_memsuffixnum,IFRN_T0,2,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),2,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T0),2,IFRBA(IFRN_A0),2,0,0,"NONE","NONE",-1);
    break;

    // T0 = *A0, 4 bytes
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T0_A0:
    if_ldu(if_memsuffixnum,IFRN_T0,4,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),4,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T0),4,IFRBA(IFRN_A0),4,0,0,"NONE","NONE",-1);
    break;

    // T1 = *A0, just one byte. A0 is next element in log.
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUB_T1_A0:
    if_ldu(if_memsuffixnum,IFRN_T1,1,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),1,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T1),1,IFRBA(IFRN_A0),1,0,0,"NONE","NONE",-1);
    break;
    
    // ditto, but signed.
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSB_T1_A0:
    if_lds(if_memsuffixnum,IFRN_T1,1,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),1,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T1),1,IFRBA(IFRN_A0),1,0,0,"NONE","NONE",-1);
    break; 
      
    // T1 = *A0, 2 bytes
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDUW_T1_A0:
    if_ldu(if_memsuffixnum,IFRN_T1,2,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),2,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T1),2,IFRBA(IFRN_A0),2,0,0,"NONE","NONE",-1);
    break;

    // ditto, but signed.
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDSW_T1_A0:
    if_lds(if_memsuffixnum,IFRN_T1,2,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),2,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T1),2,IFRBA(IFRN_A0),2,0,0,"NONE","NONE",-1);
    break;

    // T1 = *A0, 4 bytes
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_LDL_T1_A0:
    if_ldu(if_memsuffixnum,IFRN_T1,4,if_addr);
    if(exists_taint(IFRBA(IFRN_A0),4,__FILE__,__LINE__))
    transfer_taint(IFRBA(IFRN_T1),4,IFRBA(IFRN_A0),4,0,0,"NONE","NONE",-1);
    break;

    // *A0 = T0, one byte
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STB_T0_A0:
   // if_st(if_memsuffixnum,IFRN_T0,1,if_addr);
    info_flow_copy(if_addr,IFRBA(IFRN_T0),1);
    break;

    // two bytes.
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T0_A0:
    //if_st(if_memsuffixnum,IFRN_T0,2,if_addr);
    info_flow_copy(if_addr,IFRBA(IFRN_T0),2);
    break;

    // all four bytes
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T0_A0:
    if_st(if_memsuffixnum,IFRN_T0,4,if_addr);
    break;

    // *A0 = T1, one byte
    //  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STB_T1_A0:
        //if_st(if_memsuffixnum,IFRN_T1,1);
   //     info_flow_copy(if_addr,IFRBA(IFRN_T1),1);
   //     break;

    // two bytes.
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STW_T1_A0:
   // if_st(if_memsuffixnum,IFRN_T1,2,if_addr);
	info_flow_copy(if_addr,IFRBA(IFRN_T1),2);
    break;

    // all four bytes
  case INFO_FLOW_OP_MEMSUFFIX_ADDR_STL_T1_A0:
    if_st(if_memsuffixnum,IFRN_T1,4,if_addr);
    break;

    /*
      Done handling ops_mem.h stuff.
    */

    // raincheck
    // EIP = T0;
  case INFO_FLOW_OP_JMP_T0:
    // check here that EIP isn't tainted?  
    // copy info from T0 to EIP? 
    break;

    // raincheck
    // EIP = (uint32_t)PARAM1;
  case INFO_FLOW_OP_MOVL_EIP_IM:
    break;

    /*
      Skipping 64-bit
      op_movq_eip_im
      op_movq_eip_im64
    */

    /*
      No info-flow for
      op_hlt;
      op_monitor;
      op_mwait;
      op_debug;
      op_raise_interrupt;
      op_raise_exception;
      op_into;
      op_cli;
      op_sti;
      op_set_inhibit_irq;
      op_reset_inhibit_irq;
      op_rsm;
      op_boundw;  (Really?)
      op_boundl;  (Really?)

    */

    /*
    eflags = cc_table[CC_OP].compute_all();
    d = ldq(A0);
    if (d == (((uint64_t)EDX << 32) | EAX)) {
        // part_1 corresponds to this branch
        stq(A0, ((uint64_t)ECX << 32) | EBX);
        eflags |= CC_Z;
	...
    } else 
    */
  case INFO_FLOW_OP_CMPXCHG8B_PART1:
    //if_st(0,IFRN_EAX,4,if_addr);
    //if_st(0,IFRN_ECX,4,if_addr+4);
    break;

    /*
    eflags = cc_table[CC_OP].compute_all();
    d = ldq(A0);
    if (d == (((uint64_t)EDX << 32) | EAX)) {
      ...
    } else {
      // part_2 corresponds to this branch
        EDX = d >> 32;
        EAX = d;
        eflags &= ~CC_Z;
    }
    */
  case INFO_FLOW_OP_CMPXCHG8B_PART2:
    //if_ldu(0,IFRN_EAX,4,if_addr);
    // little endian -- higher order word comes 2nd
    //if_ldu(0,IFRN_EDX,4,if_addr+4);
    break;

    // T0 = 0;
  case INFO_FLOW_OP_MOVL_T0_0:
    if_delete_r4(IFRN_T0);
    break;

    /*
      No info flow for 
      op_exit_tb
    */
    
    /*
      Start handling includes of ops_template.h into op.c

      Time for all those multiple size ops 
      i.e. the 4 different includes of ops_template.h in op.c
      for SHIFT = 0,1,2,3
      which turns into q,l,w,b in ops_template.h
    */

    /*
      These are all about computing cc (flags).
      Taking a rain check for now. 
      compute_all_add
      compute_c_add
      compute_all_adc
      compute_c_adc
      compute_all_sub
      compute_c_sub
      compute_all_sbb
      compute_c_sbb
      compute_all_logic
      compute_all_inc
      compute_c_inc
      compute_all_dec
      compute_all_shl
      compute_c_shl
      compute_c_sar
      compute_all_sar
      compute_c_mul
      compute_all_mul
      
      These are jumps.  Also taking a raincheck.
      op_jb_sub
      op_jz_sub
      op_jnz_sub
      op_jbe_sub
      op_js_sub
      op_jl_sub
      op_jle_sub
      
      Loops get a raincheck, too.
      op_loopnz
      op_loopz
      op_jz_ecx
      op_jnz_ecx
    */

    // raincheck
    // these are all about setting T0 to true/false
    // based upon the relationships between condition codes.
    // T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
  case INFO_FLOW_OP_SHIFT_SETB_T0_SUB:
    // T0 = ((DATA_TYPE)CC_DST == 0);
  case INFO_FLOW_OP_SHIFT_SETZ_T0_SUB:
    // T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
  case INFO_FLOW_OP_SHIFT_SETBE_T0_SUB:
    // T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1;
  case INFO_FLOW_OP_SHIFT_SETS_T0_SUB:
    // T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
  case INFO_FLOW_OP_SHIFT_SETL_T0_SUB:
    // T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
  case INFO_FLOW_OP_SHIFT_SETLE_T0_SUB:
    if_delete_r4(IFRN_T0);
    break;

    // count = T1 & SHIFT1_MASK;
    // T0 = T0 << count;
  case INFO_FLOW_OP_SHIFT_SHL_T0_T1:
    // count = T1 & SHIFT1_MASK;
    // T0 &= DATA_MASK;
    // T0 = T0 >> count;
  case INFO_FLOW_OP_SHIFT_SHR_T0_T1:
    // count = T1 & SHIFT1_MASK;
    // src = (DATA_STYPE)T0;
    // T0 = src >> count;    
  case INFO_FLOW_OP_SHIFT_SAR_T0_T1:
    // wrong.  prolly should use SHIFT to limit spread
    if_self_compute_r4(IFRN_T0,IFRN_T1);
    break;

    /*
      Start handling includes of ops_template_mem.h into ops_template.h, 
      and thus into op.c
      MEM_WRITE is the parameterization for this include, taking on values 0,1,2 
      and undefined.
      Note that this means each of these needs to be parameterized by *both*
      if_shift and if_mem_write
    */

    // blimey. raincheck.  These fiddle with value for T0 and then (if mem_write == 1)
    // store that value at A0.  Ugh. 
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROL_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROR_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROL_T0_T1:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ROR_T0_T1:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_RCL_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_RCR_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHL_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHR_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SAR_T0_T1_CC:
    if_delete_r4(IFRN_T0);
    break;

  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHLD_T0_T1_IM_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHLD_T0_T1_ECX_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHRD_T0_T1_IM_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SHRD_T0_T1_ECX_CC:
    {
      trl_boolean okay = FALSE;
      if (if_shift == 1) { // DATA_BITS == 16
	if_delete_r4(IFRN_T0);
	okay = TRUE;
      }
      else {
	if (if_shift >= 2) { // DATA_BITS >= 32
	  if_delete_r4(IFRN_T0);
	  if_delete_r4(IFRN_T1);
	  okay = TRUE;
	}
      }
      if (okay == FALSE) {
	printf ("DATA_BITS < 16 ?\n");
	assert (1==0);
      }    
      break;
    }

    // raincheck. 
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_ADC_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_SBB_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_MEM_WRITE_CMPXCHG_T0_T1_EAX_CC:
    if_delete_r4(IFRN_T0);
    break;
    
    /*
      Done handling includes of ops_template_mem.h into ops_template.h
    */

    /*
      first, all of these have
      (use Q1 for count)
      Q1 = T1 & SHIFT_MAX
      T1 = T0 >> Q1;
      
      next, they differentiate 
      BTS: T0 |= (((target_long)1) << Q1);
      BTR: T0 &= ~(((target_long)1) << Q1);
      BTC: T0 ^= (((target_long)1) << Q1);
     */
  case INFO_FLOW_OP_SHIFT_BTS_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_BTR_T0_T1_CC:
  case INFO_FLOW_OP_SHIFT_BTC_T0_T1_CC:
    // Q1 = T1 & SHIFT_MASK
    if_delete_r4(IFRN_Q1);
    if_compute_r4(IFRN_Q1,IFRN_T1);
    // T1 = T0 >> Q1;
    if_delete_r4(IFRN_T1);
    if_compute_r4(IFRN_T1,IFRN_T0);
    if_compute_r4(IFRN_T1,IFRN_Q1);
    // T0 computed from itself and Q1.
    if_self_compute_r4(IFRN_T0,IFRN_Q1);
    break;

    // A0 += ((DATA_STYPE)T1 >> (3 + SHIFT)) << SHIFT;
  case INFO_FLOW_OP_SHIFT_ADD_BIT_A0_T1:
    if_self_compute_r4(IFRN_A0,IFRN_T1);
    break;

    // weird shit.
  case INFO_FLOW_OP_SHIFT_BSF_T0_CC:
  case INFO_FLOW_OP_SHIFT_BSR_T0_CC:
    if_delete_r4(IFRN_T1);
    if_compute_r4(IFRN_T1,IFRN_T0);
    break;

    // raincheck. 
    // DF is "direction flag" 
    // T0 = DF << SHIFT;    
  case INFO_FLOW_OP_SHIFT_MOVL_T0_DSHIFT:
    if_delete_r4(IFRN_T0);
    break;
    
  case INFO_FLOW_OP_SHIFT_IN_T0_T1:
    // port i/o 
    // I think this is handled elsewhere...
    //    if_delete_r4(IFRN_T1);
    break;

  case INFO_FLOW_OP_SHIFT_IN_DX_T0:
    // again, port i/o
    //    if_delete_r4(IFRN_T0);
    break;

    /*
      Done handling includes of ops_template.h into op.c
    */

    // T0 = (int8_t)T0;
  case INFO_FLOW_OP_MOVSBL_T0_T0:
    // sign extension?
    if_inc_r4(IFRN_T0);
    break;

    // T0 = (uint8_t)T0;
  case INFO_FLOW_OP_MOVZBL_T0_T0:
    // clear top 3 bytes
    if_delete_reg_aux(IFRN_T0,1,3);
    break;

    // T0 = (int16_t)T0;
  case INFO_FLOW_OP_MOVSWL_T0_T0:
    if_inc_r4(IFRN_T0);
    break;

    // T0 = (uint16_t)T0;    
  case INFO_FLOW_OP_MOVZWL_T0_T0:
    if_delete_reg_aux(IFRN_T0,2,2);
    break;

    // EAX = (uint32_t)((int16_t)EAX);
  case INFO_FLOW_OP_MOVSWL_EAX_AX:
    // sign extend and then mask?
    if_inc_r4(IFRN_EAX);
    break;

    /*
      Skipping 64-bit stuff.
      op_movslq_T0_T0
      op_moslq_RAX_EAX
    */

    // wtf, mate?
    // EAX = (EAX & ~0xffff) | ((int8_t)EAX & 0xffff);
  case INFO_FLOW_OP_MOVSBW_AX_AL:
    if_inc_r4(IFRN_EAX);
    break;

    // wtf isnt this a 64-bit op? 
    // EDX = (uint32_t)((int32_t)EAX >> 31);
  case INFO_FLOW_OP_MOVSLQ_EDX_EAX:
    if_self_compute_r4(IFRN_EDX,IFRN_EAX);
    break;

    // EDX = (EDX & ~0xffff) | (((int16_t)EAX >> 15) & 0xffff);
  case INFO_FLOW_OP_MOVSWL_DX_AX:
    if_self_compute_r4(IFRN_EDX,IFRN_EAX);
    break;    

    /*
      Skipping 64-bit stuff.
      op_movsqo_RDX_RAX
    */

    // ESI = (uint32_t)(ESI + T0);
  case INFO_FLOW_OP_ADDL_ESI_T0:
    if_self_compute_r4(IFRN_ESI,IFRN_T0);
    break;

    // ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff);
  case INFO_FLOW_OP_ADDW_ESI_T0:
    if_self_compute_r2(IFRN_ESI,IFRN_T0);
    break;

    // EDI = (uint32_t)(EDI + T0);
  case INFO_FLOW_OP_ADDL_EDI_T0:
    if_self_compute_r4(IFRN_EDI,IFRN_T0);
    break;

    // EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff);
  case INFO_FLOW_OP_ADDW_EDI_T0:
    if_self_compute_r2(IFRN_EDI,IFRN_T0);
    break;

    // ECX = (uint32_t)(ECX - 1);
  case INFO_FLOW_OP_DECL_ECX:
    if_inc_r4(IFRN_ECX);
    break;

    // ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff);
  case INFO_FLOW_OP_DECW_ECX:
    if_inc_r4(IFRN_ECX);
    break;

    /*
      Skipping 64-bit stuff.
      op_addq_ESI_T0
      op_addq_EDI_T0
      op_decq_ECX
    */

    // A0 = (uint32_t)(A0 + env->segs[R_SS].base);
  case INFO_FLOW_OP_ADDL_A0_SS:
    // A0 = (uint32_t)(A0 - 2);
  case INFO_FLOW_OP_SUBL_A0_2:
    // A0 = (uint32_t)(A0 - 4);
  case INFO_FLOW_OP_SUBL_A0_4:
    if_inc_r4(IFRN_A0);
    break;

    // ESP = (uint32_t)(ESP + 4)
  case INFO_FLOW_OP_ADDL_ESP_4:
    // ESP = (uint32_t)(ESP + 2);
  case INFO_FLOW_OP_ADDL_ESP_2:
    // ESP = (ESP & ~0xffff) | ((ESP + 4) & 0xffff);
  case INFO_FLOW_OP_ADDW_ESP_4:
    // ESP = (ESP & ~0xffff) | ((ESP + 2) & 0xffff);
  case INFO_FLOW_OP_ADDW_ESP_2:
    // ESP = (uint32_t)(ESP + PARAM1);
  case INFO_FLOW_OP_ADDL_ESP_IM:
    // ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff);
  case INFO_FLOW_OP_ADDW_ESP_IM:
    if_inc_r4(IFRN_ESP);
    break;

    /*
      Skipping 64-bit stuff.
      op_subq_A0_2
      op_subq_A0_8
      op_addq_ESP_8
      op_addq_ESP_im
    */

    // helper_rdtsc();
  case INFO_FLOW_OP_RDTSC:
    if_delete_r4(IFRN_EAX);
    if_delete_r4(IFRN_EDX);
    break;

    // helper_cpuid();    
  case INFO_FLOW_OP_CPUID:
    if_delete_r4(IFRN_EAX);
    if_delete_r4(IFRN_EBX);
    if_delete_r4(IFRN_ECX);
    if_delete_r4(IFRN_EDX);
    break;

    // rainchek    
    // helper_enter_level(PARAM1, PARAM2);
  case INFO_FLOW_OP_ENTER_LEVEL:
    // helper_sysenter();
  case INFO_FLOW_OP_SYSENTER:
    // helper_sysexit();
  case INFO_FLOW_OP_SYSEXIT:
    break;

    /*
      Skipping 64-bit stuff.
      op_enter64_level;
      op_syscall;
      op_sysret;
    */

    // raincheck
    // helper_rdmsr();
  case INFO_FLOW_OP_RDMSR:
    // helper_wrmsr();
  case INFO_FLOW_OP_WRMSR:
    if_delete_r4(IFRN_EAX);
    if_delete_r4(IFRN_EDX);
    break;

    // raincheck
    // bcd shite.  please.
  case INFO_FLOW_OP_AAM:
  case INFO_FLOW_OP_AAD:
  case INFO_FLOW_OP_AAA:
  case INFO_FLOW_OP_AAS:
  case INFO_FLOW_OP_DAA:
  case INFO_FLOW_OP_DAS:
    if_delete_r4(IFRN_EAX);
    break;

    // raincheck
    // segment handling stuff
  case INFO_FLOW_OP_MOVL_SEG_T0:
  case INFO_FLOW_OP_MOVL_SEG_T0_VM:
  case INFO_FLOW_OP_MOVL_T0_SEG:
    if_delete_r4(IFRN_T0);
    break;

    // rainchek
  case INFO_FLOW_OP_LSL:
    // load segment limit
  case INFO_FLOW_OP_LAR:
    // load access rights byte
    if_delete_r4(IFRN_T1);
    break;

    /*
      no info flow for?
      op_verr
      op_verw
    */

    // raincheck
  case INFO_FLOW_OP_ARPL:
    if_delete_r4(IFRN_T0);
    if_delete_r4(IFRN_T1);
    break;

    // raincheck
  case INFO_FLOW_OP_LJMP_PROTECTED_T0_T1:
    // protected mode jump
  case INFO_FLOW_OP_LCALL_REAL_T0_T1:
    // real mode call
  case INFO_FLOW_OP_LCALL_PROTECTED_T0_T1:
    // protected mode call
  case INFO_FLOW_OP_IRET_REAL:
    // real & vm86 mode iret
  case INFO_FLOW_OP_IRET_PROTECTED:
    // protected mode iret
  case INFO_FLOW_OP_LRET_PROTECTED:
    // punt.
    break;

    // raincheck
  case INFO_FLOW_OP_LLDT_T0:
    // load local descriptor table
  case INFO_FLOW_OP_LTR_T0:
    // load task descriptor table
  case INFO_FLOW_OP_MOVL_CRN_T0:
    // punting again. 
    break;

    // raincheck
  case INFO_FLOW_OP_MOVTL_T0_CR8:
    if_delete_r4(IFRN_T0);
    break;

    // raincheck
  case INFO_FLOW_OP_MOVL_DRN_T0:
    // punt 
    break;

    // raincheck
  case INFO_FLOW_OP_LMSW_T0:
    if_delete_r4(IFRN_T0);
    break;

    // raincheck
  case INFO_FLOW_OP_INVLPG_A0:
    // punt
    break;

    /*
      NB:using memsufix=_raw here?
    */

    // TRL 0806.  I *think* this all has fairly esoteric use.
    // these aren't run-of-the-mill ld/st.  Like ld/st global descriptor table addr. 
    // raincheck.
    
    // T0 = *(uint32_t *)((char *)env + PARAM1);
  case INFO_FLOW_OP_ADDR_MOVL_T0_ENV:
    // *(uint32_t *)((char *)env + PARAM1) = T0;
  case INFO_FLOW_OP_ADDR_MOVL_ENV_T0:
    // *(uint32_t *)((char *)env + PARAM1) = T1;
  case INFO_FLOW_OP_ADDR_MOVL_ENV_T1:
    // T0 = *(target_ulong *)((char *)env + PARAM1);
  case INFO_FLOW_OP_ADDR_MOVTL_T0_ENV:
    // *(target_ulong *)((char *)env + PARAM1) = T0;
  case INFO_FLOW_OP_ADDR_MOVTL_ENV_T0:
    // T1 = *(target_ulong *)((char *)env + PARAM1);
  case INFO_FLOW_OP_ADDR_MOVTL_T1_ENV:
    // *(target_ulong *)((char *)env + PARAM1) = T1;
  case INFO_FLOW_OP_ADDR_MOVTL_ENV_T1:
    break;

    // raincheck
  case INFO_FLOW_OP_CLTS:
    break; 

    /* 
       No info flow for
       op_goto_tb0
       op_goto_tb1
       op_jmp_label
       op_jnz_T0_label  IMPLICIT INFO-FLOW???
       op_jz_T0_label   DITTO!
    */

    // raincheck
  case INFO_FLOW_OP_SETO_T0_CC:    
  case INFO_FLOW_OP_SETB_T0_CC:
  case INFO_FLOW_OP_SETZ_T0_CC:
  case INFO_FLOW_OP_SETBE_T0_CC:
  case INFO_FLOW_OP_SETS_T0_CC:
  case INFO_FLOW_OP_SETP_T0_CC:
  case INFO_FLOW_OP_SETL_T0_CC:
  case INFO_FLOW_OP_SETLE_T0_CC:
    if_delete_r4(IFRN_T0);
    break;
    
    // T0 ^= 1
  case INFO_FLOW_OP_XOR_T0_1:
    if_inc_r4(IFRN_T0);
    break;

    /* 
       No info flow for
       op_set_cc_op
    */

  case INFO_FLOW_OP_MOV_T0_CC:
    if_delete_r4(IFRN_T0);
    break;

    // raincheck
    // these are all about eflags.
    // no effect upon regular regs.  
    // variants of eflags = t0
  case INFO_FLOW_OP_MOVL_EFLAGS_T0:
  case INFO_FLOW_OP_MOVW_EFLAGS_T0:
  case INFO_FLOW_OP_MOVL_EFLAGS_T0_IO:
  case INFO_FLOW_OP_MOVW_EFLAGS_T0_IO:
  case INFO_FLOW_OP_MOVL_EFLAGS_T0_CPL0:
  case INFO_FLOW_OP_MOVW_EFLAGS_T0_CPL0:
  case INFO_FLOW_OP_MOVB_EFLAGS_T0:
    // punt.
    break;

    // raincheck
    // t0 = eflags 
  case INFO_FLOW_OP_MOVL_T0_EFLAGS:
    if_delete_r4(IFRN_T0);
    break;

    /*
      No info flow for the following
      op_cld
      op_std
      op_clc
      op_stc
      op_cmc
    */

  case INFO_FLOW_OP_SALC:
    if_delete_r4(IFRN_EAX);
    break;

    /*
      Skipping boat load of FPU ops
    */

    // well, not quite. 
    // hmm this one diddles with EAX.  
  case INFO_FLOW_OP_FNSTSW_EAX:
    if_delete_r4(IFRN_EAX);
    break;

    /*
      Skipping threading support, 
      op_lock
      op_unlock

      Skipping SSE support,
      op_movo
      op_movl
      etc etc
    */
    
  case INFO_FLOW_OP_KEYBOARD_INPUT:
    {
      char alabel[1024];						        
      // construct a new keyboard label for each keycode.

            
      


      snprintf (alabel, 1024, "key-%s-%x-%x", 
		if_keyboard_label, if_key_num,if_key_val);
      push_key_label(alabel);
      if_key_num ++;      
      //      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_KEYBOARD_INPUT: if_p_orig=%p val=%x label=%s\n", 
		if_p_orig, if_key_val, alabel);
	//      }
      info_flow_label(IFRBA(IFRN_T1), 1, alabel);
      info_flow_mark_as_possibly_tainted(IFRN_T1);      
      
      if (if_key_num == 3 && if_key_val == 0x2e) {
      	foo2 = TRUE;
//	if_debug_set_med();
      }
    }
    break;

  case INFO_FLOW_OP_TLB_FILL:
	if(debug_at_least_low())
	printf("We hit a tlb fill!\r\n");
	break;
  case  INFO_FLOW_OP_SAVE_ENV:
	if(debug_at_least_low())
         printf("SAVE_ENV called outside loop\r\n");
	 if_save_env_called = TRUE;
	 break;
   case INFO_FLOW_OP_RESTORE_ENV:
	if(debug_at_least_low())
        printf("RESTORE_ENV called outside loop\r\n");
	if(!if_save_env_called_previous){
		if(debug_at_least_low())
		printf("YIPES, a restore with no save\r\n");
	}
	break;

  case INFO_FLOW_OP_NEW_KEYBOARD_LABEL:
    {
      // no need to do anything; it already happened
      break;
    }
  
  case INFO_FLOW_OP_NEW_NETWORK_LABEL:
    {
      // no need to do anything; it already happened
      break;
    }

 case INFO_FLOW_OP_NETWORK_INPUT_BYTE_T0:
      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_NETWORK_INPUT_BYTE_T0: if_p_orig=%p val=%x",  
		if_p_orig, if_byte_val);
        }
	info_flow_label(IFRBA(IFRN_T0), 1, if_network_label);
        info_flow_mark_as_possibly_tainted(IFRN_T0);
  	break;
  case INFO_FLOW_OP_NETWORK_INPUT_WORD_T0:
      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_NETWORK_INPUT_WORD_T0: if_p_orig=%p val=%x",  
		if_p_orig, if_word_val);
        }
	info_flow_label(IFRBA(IFRN_T0), 2, if_network_label);
        info_flow_mark_as_possibly_tainted(IFRN_T0);
  	break;
  case INFO_FLOW_OP_NETWORK_INPUT_LONG_T0:
      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_NETWORK_INPUT_LONG_T0: if_p_orig=%p val=%x",  
		if_p_orig, if_long_val);
        }
	info_flow_label(IFRBA(IFRN_T0), 4, if_network_label);
        info_flow_mark_as_possibly_tainted(IFRN_T0);
  	break;
  case INFO_FLOW_OP_NETWORK_INPUT_BYTE_T1:
      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_NETWORK_INPUT_BYTE_T1: if_p_orig=%p val=%x",  
		if_p_orig, if_byte_val);
        }
	info_flow_label(IFRBA(IFRN_T1), 1, if_network_label);
        info_flow_mark_as_possibly_tainted(IFRN_T1);
  	break;
  case INFO_FLOW_OP_NETWORK_INPUT_WORD_T1:
      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_NETWORK_INPUT_WORD_T1: if_p_orig=%p val=%x",  
		if_p_orig, if_word_val);
        }
	info_flow_label(IFRBA(IFRN_T1), 2, if_network_label);
        info_flow_mark_as_possibly_tainted(IFRN_T1);
  	break;
  case INFO_FLOW_OP_NETWORK_INPUT_LONG_T1:
      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_NETWORK_INPUT_LONG_T1: if_p_orig=%p val=%x",  
		if_p_orig, if_long_val);
        }
	info_flow_label(IFRBA(IFRN_T1), 4, if_network_label);
        info_flow_mark_as_possibly_tainted(IFRN_T1);
  	break;
 case INFO_FLOW_OP_NETWORK_OUTPUT_BYTE_T0:
    if(exists_taint(IFRBA(IFRN_T0),1,__FILE__,__LINE__))
	printf("DANGER! Exfiltrating taint!\r\n");
    break;
 case INFO_FLOW_OP_NETWORK_OUTPUT_WORD_T0:
    if(exists_taint(IFRBA(IFRN_T0),2,__FILE__,__LINE__))
	printf("DANGER! Exfiltrating taint!\r\n");
    break;
 case INFO_FLOW_OP_NETWORK_OUTPUT_LONG_T0:
    if(exists_taint(IFRBA(IFRN_T0),4,__FILE__,__LINE__))
	printf("DANGER! Exfiltrating taint!\r\n");
    break;
 case INFO_FLOW_OP_NETWORK_OUTPUT_BYTE_T1:
    if(exists_taint(IFRBA(IFRN_T1),1,__FILE__,__LINE__))
	printf("DANGER! Exfiltrating taint!\r\n");
    break;
 case INFO_FLOW_OP_NETWORK_OUTPUT_WORD_T1:
    if(exists_taint(IFRBA(IFRN_T1),2,__FILE__,__LINE__))
	printf("DANGER! Exfiltrating taint!\r\n");
    break;
 case INFO_FLOW_OP_NETWORK_OUTPUT_LONG_T1:
    if(exists_taint(IFRBA(IFRN_T1),4,__FILE__,__LINE__))
	printf("DANGER! Exfiltrating taint!\r\n");
    break;
  case INFO_FLOW_OP_HD_TRANSFER:
      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_HD_TRANSFER: if_p_orig=%p to=%lld from=%lld size=%d\r\n",  
		if_p_orig, if_to_val, if_from_val,if_size_val);
        }
        if(exists_taint(if_from_val,if_size_val,__FILE__,__LINE__))
		printf("WOO HOO, we're tainted!!!\r\n");
    	info_flow_copy(if_to_val, if_from_val, if_size_val);
   	break;
  case INFO_FLOW_OP_HD_TRANSFER_PART1:
      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_HD_TRANSFER_PART1: if_from_val=%lld\r\n",if_from_val);
        }
   	break;
  case INFO_FLOW_OP_HD_TRANSFER_PART2:
      if (debug_at_least_low()) {
	printf ("INFO_FLOW_OP_HD_TRANSFER_PART2: if_p_orig=%p to=%lld from=%lld size=%d\r\n",  
		if_p_orig, if_to_val, if_from_val,if_size_val);
        }
        if(exists_taint(if_from_val,if_size_val,__FILE__,__LINE__))
		printf("WOO HOO, we're tainted!!!\r\n");
    	info_flow_copy(if_to_val, if_from_val, if_size_val);
   	break;
    case INFO_FLOW_OP_X86_INSN:
	printf("Yar, we hit the mark #%d...\r\n",if_long_val); 
	spit_taint();
	break;
    case INFO_FLOW_OP_CMPXCHG_T0_T1_EAX_CC_CASE1:
//	printf("we saw CMPXCHG_T0_T1_EAX_CASE1\r\n");
//	info_flow_copy(IFRBA(IFRN_T0), IFRBA(IFRN_T1), 4);
	break;
    case INFO_FLOW_OP_CMPXCHG_T0_T1_EAX_CC_CASE2:
//	printf("we saw CMPXCHG_T0_T1_EAX_CASE2\r\n");
//	info_flow_copy(if_addr, IFRBA(IFRN_T0), 4);
	break;
    case INFO_FLOW_OP_CMPXCHG_T0_T1_EAX_CC_CASE3:
//	printf("we saw CMPXCHG_T0_T1_EAX_CASE3\r\n");
//	info_flow_compute(IFRBA(IFRN_EAX), 4, IFRBA(IFRN_T0), 4);
	break;

    case INFO_FLOW_OP_SAVE_REG:
	printf("We're saving regnum#%d to addr 0x%08x\r\n",if_regnum,if_addr);
        break;
  }
  return (if_p); 
}



